Sign in with Google
OAuth 2.0-based Google login web authentication method. Available for both iOS and Android.
How It Works
Android:
- Select Google account in external browser (or Chrome Custom Tabs)
- Receive id_token via Deep Link
- Call account registration (SocialSignIn) or account conversion (SocialChange) API with the token
iOS:
- Display in-app authentication session via ASWebAuthenticationSession
- Receive id_token via Deep Link or native callback
- Call account registration (SocialSignIn) or account conversion (SocialChange) API with the token
Unreal Implementation
// GoogleSignin.h
#pragma once
#include "CoreMinimal.h"
#include "Http.h"
#include "Json.h"
#include "JsonUtilities.h"
#include "GoogleSignin.generated.h"
DECLARE_DELEGATE_OneParam(FOnGoogleSigninSuccess, const FString&);
DECLARE_DELEGATE_TwoParams(FOnGoogleSigninError, const FString&, const FString&);
UCLASS()
class YOURPROJECT_API UGoogleSignin : public UObject
{
GENERATED_BODY()
private:
static const FString HOST_PLAYNANOO_OAUTH2REDIRECT;
static const FString OAUTH2REDIRECT_SCOPE;
FString ClientId;
FOnGoogleSigninSuccess OnSuccessCallback;
FOnGoogleSigninError OnErrorCallback;
public:
/**
* Start Google login
*/
UFUNCTION(BlueprintCallable, Category = "PlayNANOO|Account")
void Sign_in_with_Google(const FString& InClientId, FOnGoogleSigninSuccess OnSuccess, FOnGoogleSigninError OnError);
private:
void OnDeepLink(const FString& URL);
FString ExtractIdToken(const FString& URL);
void OpenURLInExternalBrowser(const FString& URL);
void SendTokenToServer(const FString& Token);
};
// GoogleSignin.cpp
#include "GoogleSignin.h"
#include "Kismet/GameplayStatics.h"
#include "Misc/Guid.h"
const FString UGoogleSignin::HOST_PLAYNANOO_OAUTH2REDIRECT = TEXT("https://www.playnanoo.com/oauth2redirect.html");
const FString UGoogleSignin::OAUTH2REDIRECT_SCOPE = TEXT("openid email profile");
void UGoogleSignin::Sign_in_with_Google(const FString& InClientId, FOnGoogleSigninSuccess OnSuccess, FOnGoogleSigninError OnError)
{
ClientId = InClientId;
OnSuccessCallback = OnSuccess;
OnErrorCallback = OnError;
// Register Deep Link listener
FCoreDelegates::ApplicationReceivedDeepLinkDelegate.AddUObject(this, &UGoogleSignin::OnDeepLink);
FString Nonce = FGuid::NewGuid().ToString(EGuidFormats::Digits);
FString AuthUrl = FString::Printf(TEXT("https://accounts.google.com/o/oauth2/v2/auth?client_id=%s&redirect_uri=%s&response_type=id_token&scope=%s&nonce=%s&prompt=select_account&login_hint="),
*ClientId,
*FGenericPlatformHttp::UrlEncode(HOST_PLAYNANOO_OAUTH2REDIRECT),
*FGenericPlatformHttp::UrlEncode(OAUTH2REDIRECT_SCOPE),
*Nonce
);
// Open in external browser (prevents 403 disallowed_useragent)
OpenURLInExternalBrowser(AuthUrl);
}
void UGoogleSignin::OnDeepLink(const FString& URL)
{
FString Token = ExtractIdToken(URL);
if (!Token.IsEmpty())
{
SendTokenToServer(Token);
// Remove Deep Link listener
FCoreDelegates::ApplicationReceivedDeepLinkDelegate.RemoveAll(this);
}
}
FString UGoogleSignin::ExtractIdToken(const FString& URL)
{
// Extract id_token from query parameter(?) or fragment(#)
FString ParamString;
if (URL.Contains(TEXT("?")))
{
int32 Index;
URL.FindChar('?', Index);
ParamString = URL.RightChop(Index + 1);
}
else if (URL.Contains(TEXT("#")))
{
int32 Index;
URL.FindChar('#', Index);
ParamString = URL.RightChop(Index + 1);
}
if (ParamString.IsEmpty())
{
return FString();
}
TArray<FString> Parts;
ParamString.ParseIntoArray(Parts, TEXT("&"), true);
for (const FString& Part : Parts)
{
if (Part.StartsWith(TEXT("id_token=")))
{
return Part.RightChop(9); // "id_token=" length
}
}
return FString();
}
void UGoogleSignin::OpenURLInExternalBrowser(const FString& URL)
{
#if PLATFORM_ANDROID
// Android-specific handling
if (JNIEnv* Env = FAndroidApplication::GetJavaEnv())
{
jstring URLString = Env->NewStringUTF(TCHAR_TO_UTF8(*URL));
FJavaWrapper::CallVoidMethod(Env, FJavaWrapper::GameActivityThis,
FJavaWrapper::FindMethod(Env, FJavaWrapper::GameActivityClassID, "AndroidThunkJava_LaunchURL", "(Ljava/lang/String;)V", false),
URLString);
Env->DeleteLocalRef(URLString);
}
#else
// Default handling (iOS, etc.)
FPlatformProcess::LaunchURL(*URL, nullptr, nullptr);
#endif
}
void UGoogleSignin::SendTokenToServer(const FString& Token)
{
// Proceed with SocialChange or SocialSignIn using token value
// SocialChange(Token, TEXT("GOOGLE"));
// or
// SocialSignIn(Token, TEXT("GOOGLE"));
OnSuccessCallback.ExecuteIfBound(Token);
}
OAuth 2.0 Parameters
| Parameter | Value | Description |
|---|---|---|
| client_id | Issued from Google Cloud Console | OAuth web client ID |
| redirect_uri | https://www.playnanoo.com/oauth2redirect.html | Redirect URL after authentication |
| response_type | id_token | Request OpenID Connect ID token |
| scope | openid email profile | Scope of user information to request |
| nonce | FGuid::NewGuid() | Random string for replay attack prevention |
| prompt | select_account | Force account selection display |
Environment Setup Required
Before using Sign in with Google, refer to the Google Environment Setup documentation to complete the following settings:
- Issue OAuth 2.0 client ID from Google Cloud Console
- Android/iOS Deep Link setup
- Redirect URI registration
Usage
1. Start Google Login
void UYourClass::StartGoogleSignIn()
{
UGoogleSignin* GoogleSignin = NewObject<UGoogleSignin>();
GoogleSignin->Sign_in_with_Google(
TEXT("Your Google Client Id"),
FOnGoogleSigninSuccess::CreateLambda([](const FString& Token)
{
UE_LOG(LogTemp, Log, TEXT("Google login successful! Token: %s"), *Token);
// Call PlayNANOO API with token
// SocialSignIn(Token, TEXT("GOOGLE"));
}),
FOnGoogleSigninError::CreateLambda([](const FString& ErrorCode, const FString& Message)
{
UE_LOG(LogTemp, Error, TEXT("Google login failed: [%s] %s"), *ErrorCode, *Message);
})
);
}
2. Link Account with Token
Call PlayNANOO API with the id_token received in the SendTokenToServer method after authentication:
New Login (SocialSignIn)
void UYourClass::SocialSignIn(const FString& Token, const FString& AccountType)
{
// First login with Google account
// AccountType: "GOOGLE"
}
Account Conversion (SocialChange)
void UYourClass::SocialChange(const FString& Token, const FString& AccountType)
{
// Convert from guest to Google member
// AccountType: "GOOGLE"
}
Reference
- Account Type Value:
PN_ACCOUNT_GOOGLE = "GOOGLE"- See Etc > Account Type Information for more details - Account Conversion: Refer to Guest > Account Conversion documentation
Platform-Specific Callback Handling
Android
- Receives callbacks via DeepLink method.
- Register callbacks to
FCoreDelegates::ApplicationReceivedDeepLinkDelegate. - If the Chrome Custom Tabs library is included, the browser opens as an in-app overlay.
- If the library is not present, an external Chrome browser opens, and the app returns via deep link after authentication.
// Register Deep Link listener
FCoreDelegates::ApplicationReceivedDeepLinkDelegate.AddUObject(this, &UGoogleSignin::OnDeepLink);
iOS
- Uses ASWebAuthenticationSession to open an in-app authentication session.
- Receives callbacks via Deep Link.
- Can be handled identically using
FCoreDelegates::ApplicationReceivedDeepLinkDelegate.
Chrome Custom Tabs Setup
To display a browser as an in-app overlay on Android, the androidx.browser:browser:1.5.0 library is required.
For detailed setup instructions, refer to the Google Environment Setup documentation.