Skip to content

Step 2. Log in

Implement login so that users can log in to the app with their Google account without signing up separately. Before you begin, complete Step 1. Set up the integration.

For Google account login, the way to get credentials and the login flow differ depending on the OS the app runs on.

OS How to get credentials Behavior flow
Android Google login Add-on Direct Token flow
iOS, macOS, Windows Web login session Authorization Code flow

On Android, the Add-on returns an id_token that the Hive Axyl authentication server can validate directly, so you log in without an exchange step. On other OSs, the web login session returns only a Google authorization code. Exchange the authorization code with Exchange external authorization codes, and then log in.

1. Get Google credentials

Get Google credentials in the way that matches the OS the app runs on.

1.1. Android

On Android, the Google login Add-on opens the OS's account selection screen and returns the id_token of the account that the user selects.

Prepare the nonce

nonce is a single-use random value that verifies that the Google id_token was issued for the current login request. Generate a new one in the app right before the login call, and pass it to the Add-on.

Encode 32 bytes of cryptographically secure random data as URL-safe base64, remove the padding, and use the resulting string as is. Google returns this string as is in the nonce claim of the id_token, so unlike Apple login, you do not convert it to a hash.

using System;
using System.Security.Cryptography;

// Encode a cryptographically secure 32-byte random value as URL-safe base64 (padding removed).
static string CreateNonce()
{
    var bytes = new byte[32];
    using (var rng = RandomNumberGenerator.Create()) rng.GetBytes(bytes);
    return Convert.ToBase64String(bytes).TrimEnd('=').Replace('+', '-').Replace('/', '_');
}

Call the login Add-on

Method

LoginAsync

Call IAndroidCredentialManagerPlugin.LoginAsync() to open the account selection screen and receive credentials. The request must contain at least one authentication option to present on the screen, and it cannot contain the same type of option twice.

Authentication option Screen type When to use
SignInWithGoogle Account selection screen that appears when the user selects the Google login button When the user selects the login button directly
GoogleId Account selection sheet that slides up from the bottom of the screen When you automatically suggest login on app entry

The GoogleId option provides additional settings that narrow down the candidate accounts. If you set FilterByAuthorizedAccounts to true, only the Google accounts that the user has already allowed for this app are presented as candidates. If you set AutoSelectEnabled to true, the account is returned right away without a screen when there is only one such account.

using Hive.Axyl.Auth.Addon.CredentialManager;
using Hive.Axyl.Core;
using UnityEngine;

// The Add-on is registered only in Android builds.
if (!HiveCore.TryResolve<IAndroidCredentialManagerPlugin>(out var google))
{
    // Not Android, or the Add-on is not registered → branch to the web login session
    return;
}

string rawNonce = CreateNonce();

var loginResult = await google.LoginAsync(new LoginRequest {
    Options = new[] {
        new CredentialOption {
            SignInWithGoogle = new SignInWithGoogleOption {
                WebClientId = "{webClientId}",
                Nonce       = rawNonce,
            },
        },
    },
});

string googleProviderToken;    // ProviderToken of the login request
string googleProviderUserId;   // ProviderUserId of the login request
switch (loginResult)
{
    case AndroidCredentialManagerServiceLoginResult.Success success
        when success.Data.Selected.GoogleIdToken is { } credential:
        googleProviderToken  = credential.IdToken;
        googleProviderUserId = credential.UniqueId;
        break;

    case AndroidCredentialManagerServiceLoginResult.UserCanceled:
        // The user closed the account selection screen → keep the login screen
        return;

    case AndroidCredentialManagerServiceLoginResult.NoCredentials:
        // No Google account available on the device → guide the user to add an account
        return;

    case AndroidCredentialManagerServiceLoginResult.Failure failure:
        HiveError err = failure.Problem;
        Debug.LogError($"[{err.Code}] {err.Message} (trace: {err.TraceId})");
        return;

    // Safety net: unknown new results (UnknownOutcome) and Success without a Google credential
    default:
        Debug.LogWarning($"Unhandled result: {loginResult.GetType().Name}");
        return;
}

For WebClientId, enter the Web application type OAuth client ID prepared in Check the Google login credentials.

Warning

Use only UniqueId as the user identifier. Id of the same credential is the account's email address, and Google does not recommend using it. The Hive Axyl authentication server compares ProviderUserId with the user identifier in the id_token, so if you put Id there, the login is rejected.

Response status

Response case Description App client handling
Success Credentials obtained successfully. Take the values from Data.Selected.GoogleIdToken. Proceed with external authentication provider login
UserCanceled The user closed the account selection screen Keep the login screen
NoCredentials There is no Google account on the device that matches the requested options Guide the user to add an account
UnknownOutcome A new result that this SDK version does not know Log it and handle it conservatively
Failure Common Failure. Cancellation by the app (Cancelled) also branches here, and the cause is stored in Failure.Problem.Code. See Common error handling. Handle according to the common error handling criteria

When the app needs to stop authentication first, such as when the user leaves the login screen, call CancelCurrentSession(). The pending LoginAsync() ends with Failure, and Failure.Problem.Code contains Cancelled.

1.2. OSs other than Android

On OSs other than Android, open Google's login page with a web login session and receive an authorization code. The authorization URL composition and the response parameters follow the OAuth 2.0 specification that Google defines, so check the required parameters in Google's official documentation.

Build the authorization URL

Login works correctly only if you put the following values in the authorization URL. For how to prepare the app to receive the redirect URI, see Prepare the redirect URI.

state filters out authentication results that the app did not start, so keep the value you created and compare it in Check the callback. If you included the PKCE code_challenge, also keep the paired codeVerifier in the app until the external authorization code exchange step.

Check the callback

The web login session only returns the callback parameters as is and does not validate them, so when you receive the callback, check state first. If the callback's state differs from the value you kept, the response did not start from this login, so stop the login. Even if state matches, stop the login if there is an error or no code. If error is access_denied, the user declined the login; any other error means the login failed.

Exchange the external authorization code

Send the callback's code to Exchange external authorization codes to convert it into credentials to use for login. Put the following values in the exchange request.

  • ProviderId: Provider.Google
  • ProviderCode: The callback's code
  • RedirectUri: A value identical, character for character, to the value you put in redirect_uri of the authorization URL
  • CodeVerifier: If you put code_challenge in the authorization URL, the paired codeVerifier. If you did not, leave it unspecified
using Hive.Axyl.Auth;
using Hive.Axyl.Auth.Addon.WebAuth;
using Hive.Axyl.Core;

if (!HiveCore.TryResolve<IExternalUserAgent>(out var webAuth))
{
    return;
}

IAuthService auth = HiveCore.Resolve<IAuthService>();

// Generate and keep the PKCE values for Google before building the authorization URL. This example uses PKCE.
var (googleVerifier, googleChallenge) = CreatePkce();

// Create and keep a new value each time you attempt login.
string state = CreateNonce();

// The app builds the authorization URL according to the Google OAuth 2.0 specification.
string authorizationUrl = BuildGoogleAuthorizationUrl(googleChallenge, state, redirectUri);

var sessionResult = await webAuth.OpenAsync(new OpenRequest {
    Url         = authorizationUrl,
    RedirectUri = redirectUri,
});
if (sessionResult is not ExternalUserAgentServiceOpenResult.Success session)
{
    // For UserCanceled and Failure handling, see [Web login session](web-auth-session.md)
    return;
}

var callback = session.Data.Parameters;

// Check state first.
if (!callback.TryGetValue("state", out var returnedState) || returnedState != state)
{
    // Not a response started by this login → stop the login
    return;
}

if (callback.TryGetValue("error", out var googleError))
{
    // If "access_denied", the user declined → keep the login screen
    // Any other value means login failed → stop the login
    return;
}

if (!callback.TryGetValue("code", out var googleCode))
{
    // No authorization code → stop the login
    return;
}

// Exchange the authorization code from the callback for credentials to use for login.
var exchange = await auth.ExchangeProviderTokenAsync(new ProviderTokenRequest {
    ProviderId   = Provider.Google,
    ProviderCode = googleCode,
    RedirectUri  = redirectUri,      // Same value as redirect_uri of the authorization URL
    CodeVerifier = googleVerifier,   // Send it because code_challenge was put in the authorization URL.
});
if (exchange is not AuthExchangeProviderTokenResult.Success exchanged)
{
    // For exchange failure handling, see [Exchange external authorization codes](provider-token-exchange.md)
    return;
}

string googleProviderToken  = exchanged.Data.ProviderToken;    // ProviderToken of the login request
string googleProviderUserId = exchanged.Data.ProviderUserId;   // ProviderUserId of the login request

CreatePkce() is a helper defined in Create a guest account, and CreateNonce() is the random value generation helper defined in Prepare the nonce. BuildGoogleAuthorizationUrl() is authorization URL generation code that the app implements itself.

2. Log in with an external authentication provider

Call Log in with an external authentication provider with the googleProviderUserId and googleProviderToken obtained in the previous step. Specify Provider.Google for ProviderId.

using Hive.Axyl.Auth;
using Hive.Axyl.Core;

IAuthService auth = HiveCore.Resolve<IAuthService>();

var (codeVerifier, codeChallenge) = CreatePkce();

var result = await auth.LoginProviderAsync(new ProviderLoginRequest {
    ProviderId          = Provider.Google,
    ProviderUserId      = googleProviderUserId,
    ProviderToken       = googleProviderToken,
    DeviceKey           = deviceKey,
    ClientId            = "{clientId}",
    CodeChallenge       = codeChallenge,
    CodeChallengeMethod = CodeChallengeMethod.S256,
});

if (result is AuthLoginProviderResult.Success success)
{
    // Login succeeded → issue tokens and activate the session.
    await StartSessionAsync(success.Data.AuthorizationCode, codeVerifier, success.Data.PlayerId);
}
// For other response cases and all call parameters, see [Log in with an external authentication provider](provider-login.md)
Note

The PKCE values generated here are used when exchanging the authorization code issued by the Hive Axyl authentication server for tokens. They are separate from the PKCE values used to exchange Google's authorization code on OSs other than Android, so do not mix the two.

For the definition of StartSessionAsync() and the session activation procedure, see Issue tokens and activate the session.

Next steps