Firebase Summit에서 발표된 모든 내용을 살펴보고 Firebase로 앱을 빠르게 개발하고 안심하고 앱을 실행하는 방법을 알아보세요. 자세히 알아보기

사용자 정의 토큰 생성

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.

Firebase를 사용하면 보안 JWT(JSON Web Token)를 사용하여 사용자 또는 기기를 인증할 수 있으므로 인증을 완벽하게 제어할 수 있습니다. 서버에서 이러한 토큰을 생성하고 클라이언트 장치로 다시 전달한 다음 이를 사용하여 signInWithCustomToken() 메서드를 통해 인증합니다.

이를 위해서는 사용자 이름 및 암호와 같은 로그인 자격 증명을 수락하고 자격 증명이 유효한 경우 사용자 지정 JWT를 반환하는 서버 끝점을 만들어야 합니다. 그런 다음 서버에서 반환된 사용자 지정 JWT를 클라이언트 장치에서 사용하여 Firebase( iOS+ , Android , web )에 인증할 수 있습니다. 인증되면 이 ID는 Firebase 실시간 데이터베이스 및 Cloud Storage와 같은 다른 Firebase 서비스에 액세스할 때 사용됩니다. 또한 JWT의 콘텐츠는 실시간 데이터베이스 규칙auth 개체와 Cloud Storage 보안 규칙request.auth 개체에서 사용할 수 있습니다.

Firebase Admin SDK를 사용하여 맞춤 토큰을 만들거나 Firebase에서 기본적으로 지원하지 않는 언어로 서버를 작성한 경우 타사 JWT 라이브러리를 사용할 수 있습니다.

시작하기 전에

맞춤 토큰은 서명에 사용된 개인 키가 Google 서비스 계정에 속하는 서명된 JWT입니다. 맞춤 토큰 서명을 위해 Firebase Admin SDK에서 사용해야 하는 Google 서비스 계정을 지정하는 방법에는 여러 가지가 있습니다.

  • 서비스 계정 JSON 파일 사용 -- 이 방법은 모든 환경에서 사용할 수 있지만 코드와 함께 서비스 계정 JSON 파일을 패키징해야 합니다. 서비스 계정 JSON 파일이 외부 당사자에게 노출되지 않도록 특별히 주의해야 합니다.
  • Admin SDK가 서비스 계정을 검색하도록 허용 -- 이 방법은 Google Cloud Functions 및 App Engine과 같이 Google에서 관리하는 환경에서 사용할 수 있습니다. Google Cloud Console을 통해 몇 가지 추가 권한을 구성해야 할 수 있습니다.
  • 서비스 계정 ID 사용 -- Google 관리 환경에서 이 방법을 사용하면 지정된 서비스 계정의 키를 사용하여 토큰에 서명합니다. 그러나 원격 웹 서비스를 사용하므로 Google Cloud Console을 통해 이 서비스 계정에 대한 추가 권한을 구성해야 할 수 있습니다.

서비스 계정 JSON 파일 사용

서비스 계정 JSON 파일에는 서비스 계정에 해당하는 모든 정보(RSA 개인 키 포함)가 포함됩니다. Firebase 콘솔에서 다운로드할 수 있습니다. 서비스 계정 JSON 파일로 Admin SDK를 초기화하는 방법에 대한 자세한 내용은 Admin SDK 설정 지침 을 따르세요.

이 초기화 방법은 광범위한 Admin SDK 배포에 적합합니다. 또한 Admin SDK에서 원격 API 호출 없이 로컬에서 사용자 지정 토큰을 만들고 서명할 수 있습니다. 이 접근 방식의 주요 단점은 코드와 함께 서비스 계정 JSON 파일을 패키징해야 한다는 것입니다. 또한 서비스 계정 JSON 파일의 개인 키는 민감한 정보이므로 기밀을 유지하기 위해 특별한 주의를 기울여야 합니다. 특히 공개 버전 관리에 서비스 계정 JSON 파일을 추가하지 마십시오.

Admin SDK가 서비스 계정을 검색하도록 허용

코드가 Google에서 관리하는 환경에 배포된 경우 Admin SDK는 맞춤 토큰에 서명하는 수단을 자동 검색하려고 시도할 수 있습니다.

  • 코드가 자바, Python 또는 Go용 App Engine 표준 환경에 배포된 경우 Admin SDK는 해당 환경에 있는 앱 ID 서비스 를 사용하여 맞춤 토큰에 서명할 수 있습니다. 앱 ID 서비스는 Google App Engine에서 앱용으로 프로비저닝한 서비스 계정을 사용하여 데이터에 서명합니다.

  • 코드가 다른 관리 환경(예: Google Cloud Functions, Google Compute Engine)에 배포된 경우 Firebase Admin SDK는 로컬 메타데이터 서버 에서 서비스 계정 ID 문자열을 자동 검색할 수 있습니다. 그런 다음 검색된 서비스 계정 ID를 IAM 서비스와 함께 사용하여 원격으로 토큰에 서명합니다.

이러한 서명 방법을 사용하려면 Google 애플리케이션 기본 자격 증명으로 SDK를 초기화하고 서비스 계정 ID 문자열을 지정하지 마십시오.

노드.js

initializeApp();

자바

FirebaseApp.initializeApp();

파이썬

default_app = firebase_admin.initialize_app()

가다

app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
	log.Fatalf("error initializing app: %v\n", err)
}

씨#

FirebaseApp.Create();

동일한 코드를 로컬에서 테스트하려면 서비스 계정 JSON 파일을 다운로드하고 이를 가리키도록 GOOGLE_APPLICATION_CREDENTIALS 환경 변수를 설정하세요.

Firebase Admin SDK가 서비스 계정 ID 문자열을 검색해야 하는 경우 코드에서 처음으로 맞춤 토큰을 생성할 때 검색합니다. 결과는 캐시되어 후속 토큰 서명 작업에 재사용됩니다. 자동 검색된 서비스 계정 ID는 일반적으로 GCP에서 제공하는 기본 서비스 계정 중 하나입니다.

명시적으로 지정된 서비스 계정 ID와 마찬가지로 자동 검색된 서비스 계정 ID에는 사용자 지정 토큰 생성이 작동하려면 iam.serviceAccounts.signBlob 권한이 있어야 합니다. 기본 서비스 계정에 필요한 권한을 부여하려면 Google Cloud Console의 IAM 및 관리자 섹션을 사용해야 할 수 있습니다. 자세한 내용은 아래 문제 해결 섹션을 참조하세요.

서비스 계정 ID 사용

애플리케이션의 다양한 부분 간에 일관성을 유지하기 위해 Google 관리 환경에서 실행할 때 토큰에 서명하는 데 키가 사용되는 서비스 계정 ID를 지정할 수 있습니다. 이렇게 하면 IAM 정책을 더 간단하고 안전하게 만들 수 있으며 코드에 서비스 계정 JSON 파일을 포함할 필요가 없습니다.

서비스 계정 ID는 Google Cloud Console 또는 다운로드한 서비스 계정 JSON 파일의 client_email 필드에서 찾을 수 있습니다. 서비스 계정 ID는 <client-id>@<project-id>.iam.gserviceaccount.com 형식의 이메일 주소입니다. Firebase 및 Google Cloud 프로젝트에서 서비스 계정을 고유하게 식별합니다.

별도의 서비스 계정 ID를 사용하여 사용자 정의 토큰을 생성하려면 아래와 같이 SDK를 초기화하십시오.

노드.js

initializeApp({
  serviceAccountId: 'my-client-id@my-project-id.iam.gserviceaccount.com',
});

자바

FirebaseOptions options = FirebaseOptions.builder()
    .setCredentials(GoogleCredentials.getApplicationDefault())
    .setServiceAccountId("my-client-id@my-project-id.iam.gserviceaccount.com")
    .build();
FirebaseApp.initializeApp(options);

파이썬

options = {
    'serviceAccountId': 'my-client-id@my-project-id.iam.gserviceaccount.com',
}
firebase_admin.initialize_app(options=options)

가다

conf := &firebase.Config{
	ServiceAccountID: "my-client-id@my-project-id.iam.gserviceaccount.com",
}
app, err := firebase.NewApp(context.Background(), conf)
if err != nil {
	log.Fatalf("error initializing app: %v\n", err)
}

씨#

FirebaseApp.Create(new AppOptions()
{
    Credential = GoogleCredential.GetApplicationDefault(),
    ServiceAccountId = "my-client-id@my-project-id.iam.gserviceaccount.com",
});

서비스 계정 ID는 민감한 정보가 아니므로 노출이 중요하지 않습니다. 그러나 지정된 서비스 계정으로 맞춤 토큰에 서명하려면 Firebase Admin SDK가 원격 서비스를 호출해야 합니다. 또한 Admin SDK가 이 호출을 수행하는 데 사용하는 서비스 계정(일반적으로 { iam.serviceAccounts.signBlob {project-name}@appspot.gserviceaccount.com 있는지도 확인해야 합니다. 자세한 내용은 아래 문제 해결 섹션을 참조하세요.

Firebase Admin SDK를 사용하여 맞춤 토큰 만들기

Firebase Admin SDK에는 맞춤 토큰을 생성하기 위한 기본 제공 메서드가 있습니다. 최소한 모든 문자열이 될 수 있지만 인증하는 사용자 또는 장치를 고유하게 식별해야 하는 uid 를 제공해야 합니다. 이 토큰은 1시간 후에 만료됩니다.

노드.js

const uid = 'some-uid';

getAuth()
  .createCustomToken(uid)
  .then((customToken) => {
    // Send token back to client
  })
  .catch((error) => {
    console.log('Error creating custom token:', error);
  });

자바

String uid = "some-uid";

String customToken = FirebaseAuth.getInstance().createCustomToken(uid);
// Send token back to client

파이썬

uid = 'some-uid'

custom_token = auth.create_custom_token(uid)

가다

client, err := app.Auth(context.Background())
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}

token, err := client.CustomToken(ctx, "some-uid")
if err != nil {
	log.Fatalf("error minting custom token: %v\n", err)
}

log.Printf("Got custom token: %v\n", token)

씨#

var uid = "some-uid";

string customToken = await FirebaseAuth.DefaultInstance.CreateCustomTokenAsync(uid);
// Send token back to client

사용자 지정 토큰에 포함할 추가 클레임을 선택적으로 지정할 수도 있습니다. 예를 들어, 아래에는 보안 규칙의 auth / request.auth 개체에서 사용할 수 있는 사용자 지정 토큰에 premiumAccount 필드가 추가되었습니다.

노드.js

const userId = 'some-uid';
const additionalClaims = {
  premiumAccount: true,
};

getAuth()
  .createCustomToken(userId, additionalClaims)
  .then((customToken) => {
    // Send token back to client
  })
  .catch((error) => {
    console.log('Error creating custom token:', error);
  });

자바

String uid = "some-uid";
Map<String, Object> additionalClaims = new HashMap<String, Object>();
additionalClaims.put("premiumAccount", true);

String customToken = FirebaseAuth.getInstance()
    .createCustomToken(uid, additionalClaims);
// Send token back to client

파이썬

uid = 'some-uid'
additional_claims = {
    'premiumAccount': True
}

custom_token = auth.create_custom_token(uid, additional_claims)

가다

client, err := app.Auth(context.Background())
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}

claims := map[string]interface{}{
	"premiumAccount": true,
}

token, err := client.CustomTokenWithClaims(ctx, "some-uid", claims)
if err != nil {
	log.Fatalf("error minting custom token: %v\n", err)
}

log.Printf("Got custom token: %v\n", token)

씨#

var uid = "some-uid";
var additionalClaims = new Dictionary<string, object>()
{
    { "premiumAccount", true },
};

string customToken = await FirebaseAuth.DefaultInstance
    .CreateCustomTokenAsync(uid, additionalClaims);
// Send token back to client

예약된 사용자 정의 토큰 이름

클라이언트에서 사용자 정의 토큰을 사용하여 로그인

사용자 지정 토큰을 만든 후 클라이언트 앱으로 보내야 합니다. 클라이언트 앱은 signInWithCustomToken() 을 호출하여 사용자 지정 토큰으로 인증합니다.

iOS+

오브젝티브-C
[[FIRAuth auth] signInWithCustomToken:customToken
                           completion:^(FIRAuthDataResult * _Nullable authResult,
                                        NSError * _Nullable error) {
  // ...
}];
빠른
Auth.auth().signIn(withCustomToken: customToken ?? "") { user, error in
  // ...
}

기계적 인조 인간

mAuth.signInWithCustomToken(mCustomToken)
        .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    // Sign in success, update UI with the signed-in user's information
                    Log.d(TAG, "signInWithCustomToken:success");
                    FirebaseUser user = mAuth.getCurrentUser();
                    updateUI(user);
                } else {
                    // If sign in fails, display a message to the user.
                    Log.w(TAG, "signInWithCustomToken:failure", task.getException());
                    Toast.makeText(CustomAuthActivity.this, "Authentication failed.",
                            Toast.LENGTH_SHORT).show();
                    updateUI(null);
                }
            }
        });

단일성

auth.SignInWithCustomTokenAsync(custom_token).ContinueWith(task => {
  if (task.IsCanceled) {
    Debug.LogError("SignInWithCustomTokenAsync was canceled.");
    return;
  }
  if (task.IsFaulted) {
    Debug.LogError("SignInWithCustomTokenAsync encountered an error: " + task.Exception);
    return;
  }

  Firebase.Auth.FirebaseUser newUser = task.Result;
  Debug.LogFormat("User signed in successfully: {0} ({1})",
      newUser.DisplayName, newUser.UserId);
});

C++

firebase::Future<firebase::auth::User*> result =
    auth->SignInWithCustomToken(custom_token);

Web version 8

firebase.auth().signInWithCustomToken(token)
  .then((userCredential) => {
    // Signed in
    var user = userCredential.user;
    // ...
  })
  .catch((error) => {
    var errorCode = error.code;
    var errorMessage = error.message;
    // ...
  });

Web version 9

import { getAuth, signInWithCustomToken } from "firebase/auth";

const auth = getAuth();
signInWithCustomToken(auth, token)
  .then((userCredential) => {
    // Signed in
    const user = userCredential.user;
    // ...
  })
  .catch((error) => {
    const errorCode = error.code;
    const errorMessage = error.message;
    // ...
  });

인증에 성공하면 사용자는 이제 사용자 지정 토큰에 포함된 uid 로 지정된 계정으로 클라이언트 앱에 로그인됩니다. 해당 계정이 이전에 존재하지 않은 경우 해당 사용자에 대한 레코드가 생성됩니다.

다른 로그인 방법(예: signInWithEmailAndPassword()signInWithCredential() )과 동일한 방식으로 실시간 데이터베이스 규칙auth 객체와 Cloud Storage 보안 규칙request.auth 객체가 사용자의 uid 로 채워집니다. 이 경우 uid 는 사용자 지정 토큰을 생성할 때 지정한 것입니다.

데이터베이스 규칙

{
  "rules": {
    "adminContent": {
      ".read": "auth.uid === 'some-uid'"
    }
  }
}

저장 규칙

service firebase.storage {
  match /b/<your-firebase-storage-bucket>/o {
    match /adminContent/{filename} {
      allow read, write: if request.auth != null && request.auth.uid == "some-uid";
    }
  }
}

맞춤 토큰에 추가 클레임이 포함된 경우 규칙의 auth.token (Firebase 실시간 데이터베이스) 또는 request.auth.token (Cloud Storage) 객체에서 참조할 수 있습니다.

데이터베이스 규칙

{
  "rules": {
    "premiumContent": {
      ".read": "auth.token.premiumAccount === true"
    }
  }
}

저장 규칙

service firebase.storage {
  match /b/<your-firebase-storage-bucket>/o {
    match /premiumContent/{filename} {
      allow read, write: if request.auth.token.premiumAccount == true;
    }
  }
}

타사 JWT 라이브러리를 사용하여 사용자 지정 토큰 만들기

백엔드가 공식 Firebase Admin SDK가 없는 언어로 되어 있는 경우에도 수동으로 맞춤 토큰을 만들 수 있습니다. 먼저 해당 언어에 대한 타사 JWT 라이브러리를 찾습니다 . 그런 다음 해당 JWT 라이브러리를 사용하여 다음 주장을 포함하는 JWT를 생성합니다.

사용자 지정 토큰 클레임
alg 연산 "RS256"
iss 발급사 프로젝트의 서비스 계정 이메일 주소
sub 주제 프로젝트의 서비스 계정 이메일 주소
aud 청중 "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat 발행 시간 UNIX epoch 이후의 현재 시간(초)
exp 만료 시간 토큰이 만료되는 UNIX epoch 이후의 시간(초)입니다. iat 보다 최대 3600초 늦을 수 있습니다.
참고: 이것은 사용자 정의 토큰 자체가 만료되는 시간만 제어합니다. 그러나 signInWithCustomToken() 을 사용하여 사용자를 로그인하면 세션이 무효화되거나 사용자가 로그아웃할 때까지 장치에 로그인된 상태로 유지됩니다.
uid 로그인한 사용자의 고유 식별자는 1-36자 길이의 문자열이어야 합니다.
claims (선택 사항) 보안 규칙 auth / request.auth 변수에 포함할 선택적 사용자 지정 클레임

다음은 Firebase Admin SDK가 지원하지 않는 다양한 언어로 맞춤 토큰을 만드는 방법에 대한 몇 가지 구현 예입니다.

PHP

php-jwt 사용:

// Requires: composer require firebase/php-jwt
use Firebase\JWT\JWT;

// Get your service account's email address and private key from the JSON key file
$service_account_email = "abc-123@a-b-c-123.iam.gserviceaccount.com";
$private_key = "-----BEGIN PRIVATE KEY-----...";

function create_custom_token($uid, $is_premium_account) {
  global $service_account_email, $private_key;

  $now_seconds = time();
  $payload = array(
    "iss" => $service_account_email,
    "sub" => $service_account_email,
    "aud" => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
    "iat" => $now_seconds,
    "exp" => $now_seconds+(60*60),  // Maximum expiration time is one hour
    "uid" => $uid,
    "claims" => array(
      "premium_account" => $is_premium_account
    )
  );
  return JWT::encode($payload, $private_key, "RS256");
}

루비

ruby-jwt 사용:

require "jwt"

# Get your service account's email address and private key from the JSON key file
$service_account_email = "service-account@my-project-abc123.iam.gserviceaccount.com"
$private_key = OpenSSL::PKey::RSA.new "-----BEGIN PRIVATE KEY-----\n..."

def create_custom_token(uid, is_premium_account)
  now_seconds = Time.now.to_i
  payload = {:iss => $service_account_email,
             :sub => $service_account_email,
             :aud => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
             :iat => now_seconds,
             :exp => now_seconds+(60*60), # Maximum expiration time is one hour
             :uid => uid,
             :claims => {:premium_account => is_premium_account}}
  JWT.encode payload, $private_key, "RS256"
end

맞춤 토큰을 만든 후 Firebase 인증에 사용할 클라이언트 앱으로 보냅니다. 이 작업을 수행하는 방법은 위의 코드 샘플을 참조하세요.

문제 해결

이 섹션에서는 개발자가 사용자 지정 토큰을 만들 때 발생할 수 있는 몇 가지 일반적인 문제와 해결 방법에 대해 간략히 설명합니다.

IAM API가 활성화되지 않음

토큰 서명을 위해 서비스 계정 ID를 지정하는 경우 다음과 유사한 오류가 발생할 수 있습니다.

Identity and Access Management (IAM) API has not been used in project
1234567890 before or it is disabled. Enable it by visiting
https://console.developers.google.com/apis/api/iam.googleapis.com/overview?project=1234567890
then retry. If you enabled this API recently, wait a few minutes for the action
to propagate to our systems and retry.

Firebase Admin SDK는 IAM API 를 사용하여 토큰에 서명합니다. 이 오류는 현재 Firebase 프로젝트에 IAM API가 활성화되어 있지 않음을 나타냅니다. 웹 브라우저에서 오류 메시지의 링크를 열고 "Enable API" 버튼을 클릭하여 프로젝트에 활성화합니다.

서비스 계정에 필요한 권한이 없습니다.

Firebase Admin SDK가 실행 중인 서비스 계정에 iam.serviceAccounts.signBlob 권한이 없으면 다음과 같은 오류 메시지가 표시될 수 있습니다.

Permission iam.serviceAccounts.signBlob is required to perform this operation
on service account projects/-/serviceAccounts/{your-service-account-id}.

이 문제를 해결하는 가장 쉬운 방법은 해당 서비스 계정(일반적으로 {project-name}@appspot.gserviceaccount.com )에 "서비스 계정 토큰 생성자" IAM 역할을 부여하는 것입니다.

  1. Google Cloud Console에서 IAM 및 관리자 페이지를 엽니다.
  2. 프로젝트를 선택하고 "계속"을 클릭하십시오.
  3. 업데이트하려는 서비스 계정에 해당하는 수정 아이콘을 클릭합니다.
  4. "다른 역할 추가"를 클릭하십시오.
  5. 검색 필터에 "서비스 계정 토큰 생성자"를 입력하고 결과에서 선택합니다.
  6. "저장"을 클릭하여 역할 부여를 확인합니다.

이 프로세스에 대한 자세한 내용은 IAM 문서 를 참조하거나 gcloud 명령줄 도구를 사용하여 역할 업데이트를 수행하는 방법을 알아보세요.

서비스 계정을 확인하지 못했습니다.

다음과 유사한 오류 메시지가 표시되면 Firebase Admin SDK가 제대로 초기화되지 않은 것입니다.

Failed to determine service account ID. Initialize the SDK with service account
credentials or specify a service account ID with iam.serviceAccounts.signBlob
permission.

SDK를 사용하여 서비스 계정 ID를 자동 검색하는 경우 메타데이터 서버가 있는 관리 Google 환경에 코드가 배포되었는지 확인하세요. 그렇지 않으면 SDK 초기화 시 서비스 계정 JSON 파일 또는 서비스 계정 ID를 지정해야 합니다.