Skip to main content

Sign in with Google

OAuth 2.0-based Google login web authentication method. Available for both iOS and Android.

How It Works

Android:

  1. Select Google account in external browser (or Chrome Custom Tabs)
  2. Receive id_token via Deep Link
  3. Call account registration (SocialSignIn) or account conversion (SocialChange) API with the token

iOS:

  1. Display in-app authentication session via ASWebAuthenticationSession
  2. Receive id_token via Deep Link or native callback
  3. 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

ParameterValueDescription
client_idIssued from Google Cloud ConsoleOAuth web client ID
redirect_urihttps://www.playnanoo.com/oauth2redirect.htmlRedirect URL after authentication
response_typeid_tokenRequest OpenID Connect ID token
scopeopenid email profileScope of user information to request
nonceFGuid::NewGuid()Random string for replay attack prevention
promptselect_accountForce 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);
})
);
}

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

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.