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

Firebase では、保護された JSON Web Token(JWT)を使用したユーザーまたは端末の認証が可能であるため、認証に対する完全な制御が得られます。サーバーでこうしたトークンを生成し、クライアント デバイスに返した後、signInWithCustomToken() メソッドで認証するためにこのトークンを使用します。

このために、ユーザー名やパスワードなどのログイン認証情報を受け入れ、認証情報が有効である場合にカスタム JWT を返すサーバー エンドポイントを作成する必要があります。このようにしてサーバーから返されたカスタム JWT は、Firebase(iOSAndroidウェブ)での認証のためにクライアント端末で使用できます。認証後、Firebase Realtime Database や Firebase Storage など他の Firebase サービスにアクセスするときにこの ID が使用されます。さらに、Firebase Realtime Database セキュリティ ルールauth オブジェクトと Cloud Storage セキュリティ ルールrequest.auth オブジェクトで JWT のコンテンツが使用可能になります。

Firebase Admin SDK でカスタム トークンを作成できます。また、Firebase でネイティブにサポートされない言語でサーバーが記述されている場合は、サードパーティの JWT ライブラリを使用できます。

準備

Firebase Admin SDK でカスタム トークンを作成するには、サービス アカウントが必要です。サービス アカウントで Admin SDK を初期化する方法の詳細については、Admin SDK の設定手順をご覧ください。

Firebase Admin SDK を使用したカスタム トークンの作成

Firebase Admin SDK には、カスタム トークンを作成するための組み込みメソッドが用意されています。最低限 uid を指定する必要があり、任意の文字列を指定できますが、認証中のユーザーまたは端末を一意に識別するものである必要があります。これらのトークンは 1 時間後に失効します。

Node.js

var uid = "some-uid";

admin.auth().createCustomToken(uid)
  .then(function(customToken) {
    // Send token back to client
  })
  .catch(function(error) {
    console.log("Error creating custom token:", error);
  });

Java

String uid = "some-uid";

FirebaseAuth.getInstance().createCustomToken(uid)
    .addOnSuccessListener(new OnSuccessListener<String>() {
        @Override
        public void onSuccess(String customToken) {
            // Send token back to client
        }
    });

Python

uid = 'some-uid'

custom_token = auth.create_custom_token(uid)

Go

client, err := app.Auth()
if err != nil {
	return "", fmt.Errorf("error getting Auth client: %v", err)
}

token, err := client.CustomToken("some-uid")
if err != nil {
	return "", fmt.Errorf("error minting custom token: %v", err)
}

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

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

Node.js

var uid = "some-uid";
var additionalClaims = {
  premiumAccount: true
};

admin.auth().createCustomToken(uid, additionalClaims)
  .then(function(customToken) {
    // Send token back to client
  })
  .catch(function(error) {
    console.log("Error creating custom token:", error);
  });

Java

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

FirebaseAuth.getInstance().createCustomToken(uid, additionalClaims)
    .addOnSuccessListener(new OnSuccessListener<String>() {
        @Override
        public void onSuccess(String customToken) {
            // Send token back to client
        }
    });

Python

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

custom_token = auth.create_custom_token(uid, additional_claims)

Go

client, err := app.Auth()
if err != nil {
	return "", fmt.Errorf("error getting Auth client: %v", err)
}

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

token, err := client.CustomTokenWithClaims("some-uid", claims)
if err != nil {
	return "", fmt.Errorf("error minting custom token: %v", err)
}

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

クライアントでのカスタム トークンを使用したログイン

カスタム トークンを作成した後、クライアント アプリに送信する必要があります。クライアント アプリは、signInWithCustomToken() を呼び出してカスタム トークンで認証します。

iOS

Objective-C

[[FIRAuth auth] signInWithCustomToken:customToken
                           completion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
  // ...
}];

Swift

Auth.auth().signIn(withCustomToken: customToken ?? "") { (user, error) in
  // ...
}

Android

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);
                }
            }
        });

Unity

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);

ウェブ

firebase.auth().signInWithCustomToken(token).catch(function(error) {
  // Handle Errors here.
  var errorCode = error.code;
  var errorMessage = error.message;
  // ...
});

認証が成功した場合、ユーザーはカスタム トークンに含まれる uid によって指定されるアカウントで、クライアント アプリにログインします。そのアカウントがまだ存在しなければ、該当ユーザーのレコードが作成されます。

その他のログイン方法(signInWithEmailAndPassword()signInWithCredential() など)と同様に、Firebase Realtime Database セキュリティ ルールauth オブジェクトと Cloud Storage セキュリティ ルールrequest.auth オブジェクトにユーザーの uid が入力されます。この場合、カスタム トークンの生成時に指定した uid が使用されます。

Database ルール

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

Storage ルール

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

カスタム トークンに追加クレームが含まれる場合、ルール内の auth.token オブジェクト(Firebase Realtime Database)または request.auth.token オブジェクト(Cloud Storage)から参照できます。

Database ルール

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

Storage ルール

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 から最大で 3,600 秒後です。
注: これは、カスタム トークン自体の有効期限が切れる時間のみを制御できます。ただし、signInWithCustomToken() を使用してユーザーにログインさせた後は、セッションが無効になるかユーザーがログアウトするまで、デバイスにログインしたままになります。
uid ログイン済みユーザーの一意の ID(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

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 での認証に使用します。設定方法については、上記のコードサンプルを参照してください。

フィードバックを送信...

ご不明な点がありましたら、Google のサポートページをご覧ください。