콘텐츠로 이동

커스텀 계정 로그인 구현하기

레시피 코드로 커스텀 계정 로그인을 구현하려면 아래 절차를 순서대로 완료하세요.

시작하기 전에 공통 사전 준비를 마치세요.

전체 흐름

각 단계에서 무엇을 설정하고 무엇을 호출하는지는 아래와 같습니다.

순서 구분 하는 일
1 Hive 콘솔 Client ID와 Client Secret 확인
2 Hive Axyl SDK 인증 모듈과 보안 저장소 모듈 설치
3 Hive Axyl SDK SDK 초기화와 모듈 등록
4 레시피 코드 레시피 폴더 복사
5 앱 코드 ClientId와 DeviceKey 준비
6 앱 서버 사용자 인증과 사용자 식별자 확정
7 Hive Axyl 서버 API, 앱 서버 인증 토큰과 grant key 발급
8 앱 코드, 레시피 코드 커스텀 계정 로그인 호출
9 앱 코드 로그인 결과 처리
10 앱 코드 동작 확인
grant key 발급부터 로그인 호출까지는 끊지 말고 이어서 처리하세요

grant key는 발급 후 60초가 지나면 만료됩니다. grant key를 미리 발급받아 두거나 사용자 입력을 기다리는 동안 들고 있지 말고, 8단계 호출 직전에 발급받으세요.

1. Hive 콘솔에서 값 확인

  • Hive 콘솔  Hive 콘솔에서 설정하거나 확인합니다.

Hive 콘솔에서 보안 키의 Client ID와 Client Secret을 확인하세요. 앱 클라이언트는 로그인할 때 Client ID를 쓰고, 앱 서버는 Hive Axyl 서버 API 인증 토큰을 발급받을 때 두 값을 모두 씁니다.

확인 항목 필수 여부 사용하는 곳 확인할 곳
Client ID 필수 7단계의 토큰 발급과 8단계의 레시피 호출 보안 키 획득
Client Secret 필수 7단계의 토큰 발급 보안 키

커스텀 계정 로그인은 로그인 설정 화면에서 활성화하거나 인증 정보를 등록하지 않습니다. 사용자를 인증하는 주체가 외부 인증 제공자가 아니라 앱 서버이기 때문입니다.

Client Secret은 앱 서버에서만 사용하세요

앱 클라이언트에는 Client ID만 넣고 Client Secret은 넣지 마세요. Client Secret은 앱 서버가 Hive Axyl 서버 API 인증 토큰을 발급받을 때만 쓰는 비밀 값이며, 앱 클라이언트에서 유출되면 악의적인 사용자가 API를 무단으로 호출할 수 있습니다.

2. SDK 모듈 설치

  • Hive Axyl SDK  Hive Axyl SDK를 앱에서 호출합니다.


    상세 절차: 모듈 설치

인증 모듈과 보안 저장소 모듈을 Unity 프로젝트에 설치하세요. 보안 저장소 모듈은 DeviceKey를 기기의 보안 저장소에 보관할 때 사용합니다.

패키지 필요 여부 역할
com.com2usplatform.hiveaxyl.core 필수 SDK 초기화와 로그인 세션 관리
com.com2usplatform.hiveaxyl.auth 필수 커스텀 계정 로그인과 토큰 발급
com.com2usplatform.hiveaxyl.storage 권장 DeviceKey의 보안 저장소 보관

커스텀 계정 로그인에는 로그인 수단별 Add-on이 필요하지 않습니다. 다른 로그인 수단을 함께 제공한다면 그 수단에 필요한 Add-on만 설치하세요. 수단별로 어떤 Add-on이 필요한지는 모듈 설치 및 초기화를 참조하세요.

앱에서 이미 안전한 저장소를 사용한다면 com.com2usplatform.hiveaxyl.storage를 설치하지 않아도 됩니다. 이 경우에도 DeviceKey를 앱 재시작 뒤에 다시 읽을 수 있어야 합니다.

3. SDK 초기화

앱 시작 지점에서 SDK를 한 번 초기화하고 인증, 토큰, 보안 저장소 모듈을 등록하세요. 레시피는 SDK를 초기화하지 않으므로, 초기화하지 않은 상태에서 호출하면 FailedPrecondition 오류로 실패합니다.

아래는 커스텀 계정 로그인에 필요한 모듈을 등록해 초기화하는 예제 코드입니다.

using Hive.Axyl.Auth;
using Hive.Axyl.Core;
using Hive.Axyl.Core.Unity;
using Hive.Axyl.Storage;

var config = CoreConfig.CreateBuilder("{appId}").Build();

HiveBootstrap.Initialize(config, builder =>
{
    builder
        .AddAuth()
        .AddToken()
        .AddSecureStorage();
});

{appId}에는 사전 준비에서 만든 App ID를 입력하세요.

AddAuth()와 AddToken()을 등록하지 않으면 레시피가 FailedPrecondition 오류로 실패합니다. 앱에서 다른 안전한 저장소를 사용한다면 AddSecureStorage()는 등록하지 않아도 됩니다.

4. 레시피 코드 설치

  • 레시피 코드  레시피 코드를 프로젝트에 복사합니다.

레시피는 패키지가 아니라 프로젝트에 복사해서 사용하는 소스 코드입니다. axyl-samples-unity 저장소에서 아래 항목을 Unity 프로젝트의 Assets/Recipes/ 아래로 복사하세요.

복사할 항목과 역할은 아래와 같습니다.

  • Recipes.asmdef: 레시피 공통 어셈블리 정의
  • AssemblyInfo.cs: 내부 헬퍼를 다른 레시피 어셈블리에 공개하는 설정
  • Helper/: 여러 레시피가 함께 사용하는 공통 코드
  • CustomLogin/: CustomLoginRecipe와 결과 유형

앱 코드에서 레시피를 호출하려면 앱 쪽 어셈블리 정의의 references에 아래 어셈블리를 추가하세요. 원본 Recipes.asmdef의 autoReferenced 값이 false이므로 앱 어셈블리가 자동으로 참조하지 않습니다.

{
  "name": "MyApp",
  "references": [
    "Hive.Axyl.Core",
    "Hive.Axyl.Auth",
    "Hive.Axyl.Storage",
    "Hive.Axyl.Samples.Recipes"
  ]
}

MyApp은 앱에서 사용하는 어셈블리 이름으로 바꾸고, 기존 설정과 참조는 유지하세요. Unity 어셈블리는 참조를 전이하지 않으므로 앱 코드가 직접 사용하는 어셈블리를 모두 여기에 적어야 합니다. Hive.Axyl.Core에는 CoreConfig와 HiveError가, Hive.Axyl.Auth에는 AddAuth()와 AddToken()이, Hive.Axyl.Storage에는 AddSecureStorage()가 들어 있습니다. AddSecureStorage()를 등록하지 않는다면 Hive.Axyl.Storage는 적지 않아도 됩니다.

CustomLogin/만 복사하면 컴파일되지 않습니다

CustomLoginRecipe는 Helper/의 PKCE 생성 코드와 세션 준비 코드를 사용합니다. Helper/, Recipes.asmdef, AssemblyInfo.cs를 함께 복사하세요.

5. ClientId와 DeviceKey 준비

CustomLoginRecipe의 생성자는 ClientId와 DeviceKey를 받으며, 두 값 중 하나라도 비어 있으면 ArgumentException을 발생시킵니다. ClientId는 1단계에서 확인한 값으로, Hive 콘솔이 프로젝트마다 발급합니다. DeviceKey는 Hive Axyl 인증 서버가 로그인 세션을 기기 단위로 구분하는 값이며, 앱이 직접 만들어 보관합니다. PKCE 값은 레시피가 호출할 때마다 한 쌍을 직접 만들어 로그인 호출과 토큰 발급 호출에 나누어 전달하므로 준비하지 않아도 됩니다.

레시피는 DeviceKey를 만들거나 저장하지 않으므로, 아래 조건에 맞게 만들고 관리하세요.

  • 기기마다 다른 값. UUID 같은 난수 권장
  • 최초 실행 때 한 번 만들어 저장하고, 이후 모든 로그인에서 재사용하는 값
  • 22자 이상 64자 이하의 길이
  • 공백과 제어 문자를 제외한 ASCII 문자로만 이루어진 값
저장소를 읽지 못했다고 새 DeviceKey로 덮어쓰지 마세요

값이 사라진 것이 아니라 읽기에만 실패했을 수 있습니다. 먼저 저장소 접근 문제를 해결하거나 다시 읽기를 시도하세요.

6. 앱 서버에서 사용자 인증

앱 서버는 자체 인증 체계로 사용자를 인증하고, 그 사용자를 가리키는 식별자를 확정합니다. 이 식별자가 Hive Axyl 계정과 앱의 인증 체계 계정을 잇는 기준이 되므로 사용자 한 명에 하나씩 고정되어야 합니다.

앱 서버가 하는 일은 아래와 같습니다.

  1. 앱 클라이언트에서 로그인 요청을 받습니다.
  2. 앱의 인증 체계로 사용자를 인증합니다.
  3. 인증된 사용자의 식별자를 확정합니다. 이 값이 7단계의 providerUserId가 되며, 1자 이상 255자 이하여야 합니다.

Hive Axyl은 이 과정에 관여하지 않습니다. 어떤 방식으로 사용자를 인증할지, 식별자를 어떤 형식으로 만들지는 앱이 정합니다. 같은 사용자가 다시 로그인할 때 같은 식별자를 보내야 같은 Player ID로 이어집니다.

7. 인증 토큰과 grant key 발급

  • Hive Axyl 서버 API  앱 서버에서 Hive Axyl 서버 API를 호출합니다.

    앱 서버  앱 서버에서 직접 구현합니다.


    상세 절차: 사전 인가 키 발급

앱 서버가 Hive Axyl 서버 API를 호출해 grant key를 발급받고 그 값을 앱 클라이언트에 전달하세요. 앱 클라이언트는 이 grant key만으로 로그인하므로, 이 호출이 없으면 8단계를 진행할 수 없습니다.

이 호출에는 Hive Axyl Server API 인증 토큰이 먼저 필요합니다. 1단계의 Client ID와 Client Secret으로 토큰을 발급받는 방법은 토큰 발급을 참조하세요.

커스텀 계정 로그인은 authType에 CUSTOM_LOGIN을 지정하고, 6단계에서 확정한 사용자 식별자를 providerUserId에 넣어 호출합니다. 요청 필드별로 넣을 값은 아래와 같습니다.

  • authType: CUSTOM_LOGIN
  • providerId: CUSTOM_PROVIDER
  • providerUserId: 6단계에서 확정한 1자 이상 255자 이하의 사용자 식별자

호출 주소, 요청 헤더, 호출 예시는 상세 절차를 참조하세요. X-App-Id 헤더에는 사전 준비에서 만든 App ID를, Authorization 헤더에는 앞에서 발급받은 Hive Axyl Server API 인증 토큰을 넣습니다.

응답의 data.grantKey를 앱 클라이언트에 전달하면 이 단계가 끝납니다.

grant key 발급이 400으로 실패하면 응답의 code 값으로 원인을 구분하세요. 이때는 grant key 대신 실패를 앱 클라이언트에 전달해 8단계를 시작하지 않도록 하세요. 오류 코드별 처리 방법은 사전 인가 키 발급의 API별 오류 코드와 계정 및 인증 응답 및 오류를 참조하세요.

grant key는 민감 정보입니다

grant key는 로그인을 승인하는 값이므로 로그나 오류 메시지에 남기지 마세요. 앱 클라이언트로 전달할 때는 HTTPS처럼 암호화된 통신을 사용하세요.

8. 커스텀 계정 로그인 호출

  • 앱 코드  앱에서 직접 구현합니다.

    레시피 코드  레시피 코드를 앱에서 호출합니다.

앱 서버에서 받은 grant key를 LoginWithCustomAsync()에 전달하세요. 이 호출 하나로 로그인과 토큰 발급, 세션 활성화까지 끝납니다.

사용자가 화면을 닫거나 로그인을 취소할 때 기다리기를 멈출 수 있도록 CancellationTokenSource를 함께 준비하세요.

앱 서버에서 grant key를 받아 오는 통신 코드는 앱이 직접 만듭니다. 7단계에서 앱 서버가 받은 data.grantKey를 그대로 돌려주기만 하면 됩니다. 아래 예제 코드는 이 통신 코드를 appServerClient라는 이름으로 부릅니다.

using System.Threading;
using Hive.Axyl.Samples.Recipes;

var recipe = new CustomLoginRecipe(clientId, deviceKey);

var cancellation = new CancellationTokenSource();
CancellationToken token = cancellation.Token;

// 6~7단계를 거쳐 앱 서버가 발급받은 grant key를 가져옵니다.
string grantKey = await appServerClient.RequestCustomLoginGrantKeyAsync(token);

LoginWithCustomOutcome outcome = await recipe.LoginWithCustomAsync(grantKey, token);

if (outcome.Status == LoginWithCustomStatus.Success)
{
    long playerId = outcome.PlayerId;
    // 세션까지 준비된 상태입니다. 로그인 후 화면으로 이동합니다.
}

화면을 닫거나 사용자가 취소를 선택할 때 cancellation.Cancel()을 호출하고, 호출이 끝나면 cancellation.Dispose()로 정리하세요.

레시피가 내부에서 수행하는 작업은 아래와 같습니다.

구분 호출 확인할 곳
레시피 코드 PKCE 값 한 쌍을 만들어 로그인 호출과 토큰 발급 호출에 나눠 전달 호출 파라미터값 준비
Hive Axyl SDK LoginCustomProviderAsync()로 grant key를 제출해 인가 코드 획득 커스텀 계정 로그인
Hive Axyl SDK IssueTokenAsync()로 인가 코드를 액세스 토큰과 리프레시 토큰으로 교환 토큰 발급과 세션 활성화
Hive Axyl SDK SetSession()으로 로그인 세션 활성화 토큰 발급과 세션 활성화

레시피는 서버를 호출하기 전에 전달받은 grant key가 비어 있지 않은지, 그리고 3단계에서 등록한 SDK 모듈이 준비되어 있는지를 먼저 확인합니다. 둘 중 하나라도 문제가 있으면 서버를 호출하지 않고 바로 실패로 끝납니다.

Success가 반환되면 세션까지 준비된 상태이므로 토큰 발급이나 세션 활성화 코드를 따로 호출하지 마세요.

위 표의 상세 절차는 Hive Axyl SDK 메서드를 직접 호출할 때를 기준으로 쓰여 있습니다. PKCE 값을 만드는 작업처럼 레시피가 대신하는 단계는 앱에서 다시 구현하지 마세요. 각 호출이 무엇을 주고받는지 확인할 때만 참조하세요.

9. 로그인 결과 처리

  • 앱 코드  앱에서 직접 구현합니다.


    상세 절차: HiveError 정보

LoginWithCustomOutcome은 Status로 로그인 결과를 알려 줍니다. FailedStep은 진단용 값이므로 앱의 정상 흐름을 분기하는 기준으로 사용하지 마세요.

Status 확인할 값 앱 처리
Success PlayerId, IsBlocked 이용 제한 상태가 아니면 로그인 후 화면으로 이동합니다.
BusinessOutcome BusinessOutcome, UnknownOutcomeCode 거절 사유에 맞게 분기하고, 모르는 값은 실패로 처리해 기록합니다.
Failure Error.Code, Error.TraceId 기술 문제를 기록하고 재시도 흐름을 제공합니다.

IsBlocked가 true이면 이용이 제한된 사용자입니다. 제한 사유와 기간을 확인하고 앱 진입을 차단하는 방법은 이용 제한을 참조하세요.

레시피는 새로 만들어진 계정인지 이미 있던 계정인지는 알려 주지 않습니다. 앱이 둘을 구분해야 한다면 6단계의 사용자 식별자에 연결해 둔 PlayerId와 반환된 PlayerId를 비교하세요. 사용자 식별자를 만드는 규칙이 바뀌면 같은 사용자에게도 새 PlayerId가 발급되지만, 이때 Hive Axyl은 오류를 반환하지 않기 때문입니다.

거절 사유별 처리

Status가 BusinessOutcome이면 BusinessOutcome 값으로 거절 사유를 구분합니다. 사유마다 다시 시도할 수 있는지가 다르므로 값을 확인하고 분기하세요.

BusinessOutcome 의미 앱 처리
InvalidGrantKey grant key가 만료되었거나 이미 사용되었거나, 서버가 알지 못하는 값이거나 요청 정보와 맞지 않습니다. 6~7단계를 다시 거쳐 새 grant key를 받아 재시도합니다. 같은 결과가 반복되면 7단계의 providerId와 providerUserId 값을 확인합니다.
TemporarilyUnavailable grant key는 사용되었지만 토큰 발급이 일시적으로 불가능한 상태입니다. 잠시 후 새 grant key를 받아 처음부터 다시 시도합니다.
IpBlocked 접속 IP가 차단되었습니다. 접속이 제한되었다는 안내 화면을 사용자에게 표시합니다.
ServiceTerminated 서비스가 종료된 앱입니다. 사용자에게 서비스 종료 안내를 표시하고, 앱 운영자에게 서비스 운영 상태 확인을 요청합니다.
InvalidClient, AppNotFound, ProviderConfigNotFound, ProviderNotSupported 앱의 콘솔 설정이 요청과 맞지 않습니다. 1단계의 Client ID와 로그인 설정을 확인합니다.
UnsupportedGrantType, InvalidAuthorizationCode, ExpiredAuthorizationCode, CodeChallengeMismatch, InvalidRefreshToken 토큰 발급 단계에서 거절되었습니다. 새 grant key를 받아 로그인을 다시 시작합니다.
Unrecognized 이 레시피가 해석하지 않는 결과입니다. 실패로 처리하고 기록합니다.
같은 grant key로 다시 호출하지 마세요

grant key는 한 번만 사용할 수 있습니다. IsGrantKeyRejected가 true이면 서버가 grant key를 거절한 경우이므로 새 값이 필요합니다. false라고 해서 전달한 값을 다시 쓸 수 있다는 뜻은 아닙니다. 토큰 발급에서 실패하거나 호출이 취소된 경우에도 grant key는 이미 사용된 상태일 수 있으므로, 재시도할 때는 항상 새로 발급받으세요.

CancellationToken으로 로그인을 취소하면 Status는 Failure가 되며, 취소를 레시피가 처리한 경우 Error.Code는 HiveErrorCode.Cancelled가 됩니다.

UnknownOutcomeCode와 RawJson은 사용자에게 표시하지 마세요. 앱 오류 기록이 필요한 경우에만 사용하고, 모르는 결과를 이미 아는 결과로 추정하지 마세요. UnknownOutcomeCode가 비어 있지 않으면 서버가 이 SDK 버전이 모르는 결과를 보낸 것이고, 비어 있으면 레시피가 아직 다루지 않는 결과입니다.

10. 동작 확인

  • 앱 코드  앱에서 동작을 확인합니다.

같은 사용자가 언제 로그인해도 같은 PlayerId로 이어지는지, 그리고 사용한 grant key가 재사용되지 않는지를 확인하세요. DeviceKey 보관과 재사용까지 검증하려면 실제 기기에서 확인하세요. Unity 에디터에서는 기기 보안 저장소가 없어 ISecureStorage가 등록되지 않습니다.

  1. 앱의 인증 체계 계정으로 처음 로그인하고 Success와 PlayerId를 확인하세요.
  2. 앱을 완전히 종료한 뒤 다시 실행하세요.
  3. 같은 계정으로 다시 로그인하고 1번과 같은 PlayerId가 반환되는지 확인하세요.
  4. grant key 하나를 받아 LoginWithCustomAsync()를 연속해서 두 번 호출하고, 두 번째 호출의 IsGrantKeyRejected가 true인지 확인하세요.

4번 확인은 grant key가 만료되기 전인 60초 안에 끝내세요. 이때에도 grant key는 메모리에만 두고 로그에 남기지 마세요.

다음 단계

로그인한 사용자가 앱을 다시 실행할 때 로그인 화면을 건너뛰도록 하려면 자동 로그인을 참조하세요.

로그인한 계정에서 빠져나와 다른 계정으로 로그인하도록 하려면 로그아웃 활용 가이드를 참조하세요.

이미 사용 중인 Player ID에 커스텀 계정을 연결해야 한다면 커스텀 계정 연동을 참조하세요.