Firebase Summit で発表されたすべての情報をご覧ください。Firebase を使用してアプリ開発を加速し、自信を持ってアプリを実行する方法を紹介しています。詳細

カスタムトークンを作成する

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

Firebase では、安全な JSON Web トークン (JWT) を使用してユーザーまたはデバイスを認証できるため、認証を完全に制御できます。これらのトークンをサーバーで生成し、クライアント デバイスに戻してから、それらを使用してsignInWithCustomToken()メソッドを介して認証します。

これを実現するには、ユーザー名やパスワードなどのサインイン資格情報を受け入れるサーバー エンドポイントを作成し、資格情報が有効な場合はカスタム JWT を返す必要があります。サーバーから返されたカスタム JWT は、クライアント デバイスで Firebase ( iOS+Androidweb ) で認証するために使用できます。認証されると、Firebase Realtime Database や Cloud Storage などの他の Firebase サービスにアクセスするときに、この ID が使用されます。さらに、JWT のコンテンツは、 Realtime Database ルール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 が管理する環境で使用する場合、このメソッドは指定されたサービス アカウントのキーを使用してトークンに署名します。ただし、リモート Web サービスを使用するため、Google Cloud Console を介してこのサービス アカウントに追加の権限を構成する必要がある場合があります。

サービス アカウント JSON ファイルの使用

サービス アカウントの JSON ファイルには、サービス アカウントに対応するすべての情報 (RSA 秘密鍵を含む) が含まれます。 Firebase コンソールからダウンロードできます。サービス アカウントの JSON ファイルを使用して Admin SDK を初期化する方法の詳細については、 Admin SDK のセットアップ手順に従ってください。

この初期化方法は、幅広い Admin SDK 展開に適しています。また、リモート API 呼び出しを行わずに、Admin SDK がローカルでカスタム トークンを作成して署名できるようにします。このアプローチの主な欠点は、コードとともにサービス アカウントの JSON ファイルをパッケージ化する必要があることです。また、サービス アカウントの JSON ファイル内の秘密鍵は機密情報であるため、機密を保持するために特別な注意を払う必要があることに注意してください。具体的には、サービス アカウントの JSON ファイルをパブリック バージョン管理に追加することは控えてください。

Admin SDK がサービス アカウントを検出できるようにする

コードが Google によって管理されている環境にデプロイされている場合、Admin SDK はカスタム トークンに署名する手段を自動検出しようとすることができます。

  • コードが Java、Python、または Go の App Engine スタンダード環境にデプロイされている場合、Admin SDK はその環境にあるApp Identity サービスを使用してカスタム トークンに署名できます。 App Identity サービスは、Google App Engine によってアプリ用にプロビジョニングされたサービス アカウントを使用してデータに署名します。

  • コードが他のマネージド環境 (Google Cloud Functions、Google Compute Engine など) にデプロイされている場合、Firebase Admin SDK はローカルメタデータ サーバーからサービス アカウント ID 文字列を自動検出できます。検出されたサービス アカウント ID は、IAM サービスと組み合わせて使用​​され、リモートでトークンに署名します。

これらの署名方法を利用するには、SDK を Google アプリケーションのデフォルト認証情報で初期化し、サービス アカウント ID 文字列を指定しないでください。

Node.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)
}

C#

FirebaseApp.Create();

同じコードをローカルでテストするには、サービス アカウントの JSON ファイルをダウンロードし、それを指すようにGOOGLE_APPLICATION_CREDENTIALS環境変数を設定します。

Firebase Admin SDK がサービス アカウント ID 文字列を検出する必要がある場合は、コードが初めてカスタム トークンを作成するときに検出します。結果はキャッシュされ、後続のトークン署名操作で再利用されます。通常、自動検出されたサービス アカウント ID は、Google Cloud によって提供されるデフォルトのサービス アカウントの 1 つです。

明示的に指定されたサービス アカウント 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 を初期化します。

Node.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)
}

C#

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

サービス アカウント ID は機密情報ではないため、公開されることは重要ではありません。ただし、指定されたサービス アカウントでカスタム トークンに署名するには、Firebase Admin SDK がリモート サービスを呼び出す必要があります。さらに、この呼び出しを行うために Admin SDK が使用しているサービス アカウント (通常は { {project-name}@appspot.gserviceaccount.com ) にiam.serviceAccounts.signBlob権限があることも確認する必要があります。詳細については、以下のトラブルシューティングのセクションを参照してください。

Firebase Admin SDK を使用してカスタム トークンを作成する

Firebase Admin SDK には、カスタム トークンを作成するためのメソッドが組み込まれています。少なくともuidを指定する必要があります。これは任意の文字列ですが、認証するユーザーまたはデバイスを一意に識別する必要があります。これらのトークンは 1 時間後に期限切れになります。

Node.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)

C#

var uid = "some-uid";

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

オプションで、カスタム トークンに含める追加のクレームを指定することもできます。たとえば、以下では、 premiumAccountフィールドがカスタム トークンに追加されており、セキュリティ ルールのauth / request.authオブジェクトで使用できます。

Node.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)

C#

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+

Objective-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() ) など) と同様に、 Realtime Database ルール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 Realtime Database) または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 エポックからの現在の時刻 (秒単位)
exp有効期限トークンの有効期限が切れる UNIX エポックからの時間 (秒単位)。 iatより最大 3600 秒遅れる場合があります。
注: これは、カスタム トークン自体の有効期限が切れる時間を制御するだけです。ただし、 signInWithCustomToken()を使用してユーザーをサインインすると、セッションが無効になるか、ユーザーがサインアウトするまで、デバイスにサインインしたままになります。
uidサインインしているユーザーの一意の識別子は、1 ~ 128 文字の長さの文字列である必要があります。 uidが短いほど、パフォーマンスが向上します。
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 が有効になっていないことを示しています。エラー メッセージのリンクを Web ブラウザーで開き、[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. 検索フィルターに「Service Account Token Creator」と入力し、結果から選択します。
  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 を指定してください。