콘텐츠로 이동

2단계. 로그인

사용자가 별도의 회원가입 없이 Google Play Games 프로필로 앱에 로그인하도록 구현합니다. 시작하기 전에 1단계. 연동 환경 구성을 마치세요.

Google Play Games 로그인은 Android에서만 동작하며, Add-on이 서버 교환용 인가 코드를 돌려주므로 Authorization Code 흐름을 따릅니다.

1. Google Play Games 자격 증명 획득

Google Play Games 로그인 Add-on은 Play Games의 인증 작업을 세 가지 메서드로 나누어 제공합니다. 앱은 이 메서드를 순서대로 호출해 서버 교환용 인가 코드를 받습니다.

  1. IsAuthenticatedAsync(): 현재 Play Games 인증 상태를 화면 없이 확인
  2. SignInAsync(): Play Games 계정 선택 화면 표시. 이미 인증된 상태라면 화면 없이 바로 종료
  3. RequestServerSideAccessAsync(): 인증된 상태에서 서버 교환용 인가 코드 요청

1.1. 인증 상태 확인과 로그인

IsAuthenticatedAsync()로 상태를 먼저 확인하고, 인증되지 않았다면 SignInAsync()로 로그인 화면을 띄웁니다. SignInAsync()는 이미 인증된 경우 화면 없이 즉시 끝나므로 상태 확인을 건너뛰고 바로 호출해도 됩니다. 다만 상태를 먼저 확인하면 로그인 화면이 나타나는 시점을 앱이 직접 통제할 수 있습니다.

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

// Add-on은 Android 빌드에서만 등록됩니다.
if (!HiveCore.TryResolve<IGooglePlayGamesPlugin>(out var gpg))
{
    // Android가 아니거나 Add-on이 등록되지 않음 → 다른 로그인 수단 제시
    return;
}

var authState = await gpg.IsAuthenticatedAsync(new IsAuthenticatedRequest());

if (authState is GooglePlayGamesServiceIsAuthenticatedResult.NotAuthenticated)
{
    var signIn = await gpg.SignInAsync(new SignInRequest());
    switch (signIn)
    {
        case GooglePlayGamesServiceSignInResult.Success:
            break;   // 인증 완료 → 인가 코드 요청으로 진행

        case GooglePlayGamesServiceSignInResult.UserCanceled:
            // 사용자가 Play Games 로그인 화면을 닫음 → 로그인 화면 유지
            return;

        case GooglePlayGamesServiceSignInResult.NotAuthenticated:
            // 로그인 화면 없이 인증이 끝났으나 여전히 미인증 → 다른 로그인 수단 제시
            return;

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

        // 안전망: 처리하지 않은 결과 및 알 수 없는 신규 결과(UnknownOutcome)
        default:
            Debug.LogWarning($"처리되지 않은 결과: {signIn.GetType().Name}");
            return;
    }
}
else if (authState is GooglePlayGamesServiceIsAuthenticatedResult.Failure stateFailure)
{
    HiveError stateError = stateFailure.Problem;
    Debug.LogError($"[{stateError.Code}] {stateError.Message} (trace: {stateError.TraceId})");
    return;
}

로그인 화면이 떠 있는 동안 앱이 인증을 중단해야 한다면 CancelCurrentSignIn()을 호출합니다. 대기 중이던 SignInAsync()는 Failure로 끝나고 Failure.Problem.Code에 Cancelled가 담깁니다.

응답 상태

GooglePlayGamesServiceIsAuthenticatedResult와 GooglePlayGamesServiceSignInResult의 응답 케이스는 switch 구문으로 처리하는 것을 권장합니다.

메서드 및 응답 케이스 설명 앱 클라이언트 대응
IsAuthenticatedAsync() → Success 이미 인증된 상태 바로 인가 코드 요청으로 진행
IsAuthenticatedAsync() → NotAuthenticated 인증되지 않은 상태. 오류가 아닙니다. SignInAsync() 호출
SignInAsync() → Success 로그인 성공 인가 코드 요청으로 진행
SignInAsync() → UserCanceled 사용자가 Play Games 로그인 화면을 닫은 경우 로그인 화면 유지
SignInAsync() → NotAuthenticated 로그인 화면 없이 끝났으나 여전히 미인증인 경우 다른 로그인 수단 제시
UnknownOutcome 이 SDK 버전이 알지 못하는 신규 결과 로깅 후 보수적으로 처리
Failure 공통 Failure입니다. 앱이 취소한 경우(Cancelled)도 여기로 분기합니다. 공통 오류 처리를 참조하세요. 공통 오류 처리 기준에 따라 처리

1.2. 서버 교환용 인가 코드 요청

Method

RequestServerSideAccessAsync

인증을 마친 뒤 RequestServerSideAccessAsync()를 호출해 서버 교환용 인가 코드를 받습니다. 이 인가 코드는 외부 인증 코드 교환에서 ProviderCode로 사용합니다.

필드명 타입 필수 여부 설명
WebClientId string Required Google Play Games 로그인 인증 정보 확인에서 준비한 웹 애플리케이션 유형 OAuth 클라이언트 ID. 비워 두면 ArgumentException이 발생합니다.
ForceRefreshToken bool Optional 리프레시 토큰을 새로 발급받을지 여부. 처음 교환하거나 이전 교환이 실패했다면 true로 지정합니다. 생략하면 false입니다.
using Hive.Axyl.Auth.Addon.GPG;
using Hive.Axyl.Core;
using UnityEngine;

// Add-on은 Android 빌드에서만 등록됩니다.
if (!HiveCore.TryResolve<IGooglePlayGamesPlugin>(out var gpg))
{
    return;
}

var accessResult = await gpg.RequestServerSideAccessAsync(
    new RequestServerSideAccessRequest {
        WebClientId       = "{webClientId}",
        ForceRefreshToken = true,
    });

string serverAuthCode;   // 외부 인증 코드 교환의 ProviderCode
switch (accessResult)
{
    case GooglePlayGamesServiceRequestServerSideAccessResult.Success success:
        serverAuthCode = success.Data.ServerAuthCode;
        break;

    case GooglePlayGamesServiceRequestServerSideAccessResult.NotAuthenticated:
        // 인증 상태가 아님 → SignInAsync를 먼저 호출하고 다시 시도
        return;

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

    // 안전망: 처리하지 않은 결과 및 알 수 없는 신규 결과(UnknownOutcome)
    default:
        Debug.LogWarning($"처리되지 않은 결과: {accessResult.GetType().Name}");
        return;
}
Warning

ServerAuthCode는 한 번만 사용할 수 있는 인증 정보입니다. 로그, 크래시 리포트, 분석 이벤트에 남기지 마세요.

응답 상태

응답 케이스 설명 앱 클라이언트 대응
Success 인가 코드 발급 성공. Data.ServerAuthCode를 ProviderCode로 사용합니다. 외부 인증 코드 교환 진행
NotAuthenticated 인증 상태가 아닌 경우 SignInAsync() 호출 후 재시도
UnknownOutcome 이 SDK 버전이 알지 못하는 신규 결과 로깅 후 보수적으로 처리
Failure 공통 Failure입니다. Play Games 설정이 갖춰지지 않은 경우(FailedPrecondition)도 여기로 분기하며 원인은 Failure.Problem.Code에 담깁니다. 공통 오류 처리를 참조하세요. 공통 오류 처리 기준에 따라 처리

2. 외부 인증 코드 교환

받은 인가 코드를 외부 인증 코드 교환으로 보내 로그인에 사용할 자격 증명으로 바꿉니다. ProviderId에는 Provider.GooglePlayGames를, RedirectUri에는 Google Play Games 로그인 인증 정보 확인에서 웹 애플리케이션 유형 OAuth 클라이언트에 등록한 리디렉션 URI를 그대로 넣습니다.

Google Play Games는 이 단계에서 PKCE를 사용하지 않으므로 CodeVerifier를 넣지 않습니다.

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

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

var exchange = await auth.ExchangeProviderTokenAsync(new ProviderTokenRequest {
    ProviderId   = Provider.GooglePlayGames,
    ProviderCode = serverAuthCode,
    RedirectUri  = redirectUri,
});
if (exchange is not AuthExchangeProviderTokenResult.Success exchanged)
{
    // 교환 실패 처리는 [외부 인증 코드 교환](provider-token-exchange.md) 참조
    return;
}

string gpgProviderToken  = exchanged.Data.ProviderToken;    // 로그인 요청의 ProviderToken
string gpgProviderUserId = exchanged.Data.ProviderUserId;   // 로그인 요청의 ProviderUserId

3. 외부 인증 제공자 로그인

교환으로 얻은 gpgProviderUserId와 gpgProviderToken으로 외부 인증 제공자 로그인을 호출합니다. ProviderId에는 Provider.GooglePlayGames를 지정합니다.

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.GooglePlayGames,
    ProviderUserId      = gpgProviderUserId,
    ProviderToken       = gpgProviderToken,
    DeviceKey           = deviceKey,
    ClientId            = "{clientId}",
    CodeChallenge       = codeChallenge,
    CodeChallengeMethod = CodeChallengeMethod.S256,
});

if (result is AuthLoginProviderResult.Success success)
{
    // 로그인 성공 → 토큰을 발급하고 세션을 활성화합니다.
    await StartSessionAsync(success.Data.AuthorizationCode, codeVerifier, success.Data.PlayerId);
}
// 그 밖의 응답 케이스와 전체 호출 파라미터는 [외부 인증 제공자 로그인](provider-login.md) 참조
Note

여기에서 생성하는 PKCE 값은 Hive Axyl 인증 서버가 발급한 인가 코드를 토큰으로 교환할 때 사용합니다. 앞 단계의 서버 교환용 인가 코드와는 관계가 없습니다.

CreatePkce()는 게스트 계정 생성에서 정의한 헬퍼이고, StartSessionAsync()의 정의와 세션 활성화 절차는 토큰 발급과 세션 활성화를 참조하세요.

다음 단계