メインコンテンツへスキップ
このチュートリアルでは、ネイティブアプリ、モバイルアプリ、またはシングルページアプリから、PKCE を使用する認可コードフローを使って独自の API を呼び出す方法を説明します。フローの仕組みと、これを使用すべき理由については、Authorization Code Flow with Proof Key for Code Exchange (PKCE) を参照してください。ネイティブアプリ、モバイルアプリ、またはシングルページアプリにログインを追加する方法については、Add Login Using Authorization Code Flow with PKCE を参照してください。
Auth0 では、次を使用してアプリに PKCE を使用する認可コードフローを簡単に実装できます。

前提条件

このチュートリアルを始める前に:
  • Auth0 にアプリケーションを登録する
    • アプリケーションの種類に応じて、Application TypeNative または Single-Page App を選択します。
    • Allowed Callback URL{yourCallbackUrl} を追加します。コールバック URL の形式は、アプリケーションの種類とプラットフォームによって異なります。アプリケーションの種類およびプラットフォームごとの形式について詳しくは、Native/Mobile クイックスタートSingle-Page App クイックスタート を参照してください。
    • アプリケーションの Grant Types認可コード が含まれていることを確認します。手順については、Grant Types を更新する を参照してください。
    • アプリケーションでリフレッシュトークンを使用できるようにするには、アプリケーションの Grant Typesリフレッシュトークン が含まれていることを確認します。手順については、Grant Types を更新する を参照してください。リフレッシュトークンの詳細については、Refresh Tokens を参照してください。
  • Auth0 に API を登録する
    • API が以前のトークンの有効期限が切れたときに新しいトークンを取得できるよう、API でリフレッシュトークンを受け取れるようにするには、Allow Offline Access を有効にします。

手順

  1. code verifier を作成: トークンをリクエストするために Auth0 に送信する code_verifier を生成します。
  2. code challenge を作成: Auth0 に送信して authorization_code をリクエストするための code_challenge を、code_verifier から生成します。
  3. ユーザーを認可: ユーザーの認可を取得し、authorization_code とともにアプリへリダイレクトします。
  4. トークンをリクエスト: authorization_codecode_verifier を使ってトークンを取得します。
  5. API を呼び出す: 取得したアクセストークンを使用して API を呼び出します。
  6. トークンを更新: 既存のトークンの有効期限が切れたら、リフレッシュトークンを使用して新しいトークンをリクエストします。
任意: サンプルのユースケースを確認

code verifier を作成する

code_verifier を作成します。これは、後でトークンをリクエストするために Auth0 に送信する、暗号学的にランダムな Base64 エンコード済みのキーです。

JavaScript サンプル

// 依存関係: Node.js crypto モジュール
// https://nodejs.org/api/crypto.html#crypto_crypto
function base64URLEncode(str) {
    return str.toString('base64')
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=/g, '');
}
var verifier = base64URLEncode(crypto.randomBytes(32));

Java の例

// 依存関係: Apache Commons Codec
// https://commons.apache.org/proper/commons-codec/
// Base64クラスをインポートします。
// import org.apache.commons.codec.binary.Base64;
SecureRandom sr = new SecureRandom();
byte[] code = new byte[32];
sr.nextBytes(code);
String verifier = Base64.getUrlEncoder().withoutPadding().encodeToString(code);

Android のサンプル

// https://developer.android.com/reference/android/util/Base64 を参照
// Base64クラスをインポートする
// import android.util.Base64;
SecureRandom sr = new SecureRandom();
byte[] code = new byte[32];
sr.nextBytes(code);
String verifier = Base64.encodeToString(code, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);

Swift 5 のサンプル

var buffer = [UInt8](repeating: 0, count: 32)
_ = SecRandomCopyBytes(kSecRandomDefault, buffer.count, &buffer)
let verifier = Data(buffer).base64EncodedString()
    .replacingOccurrences(of: "+", with: "-")
    .replacingOccurrences(of: "/", with: "_")
    .replacingOccurrences(of: "=", with: "")

Objective-C のサンプル

NSMutableData *data = [NSMutableData dataWithLength:32];
int result __attribute__((unused)) = SecRandomCopyBytes(kSecRandomDefault, 32, data.mutableBytes);
NSString *verifier = [[[[data base64EncodedStringWithOptions:0]
                        stringByReplacingOccurrencesOfString:@"+" withString:@"-"]
                        stringByReplacingOccurrencesOfString:@"/" withString:@"_"]
                        stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]];

code challenge を生成する

Auth0 に送信して authorization_code をリクエストするため、code_verifier から code_challenge を生成します。

Javascript サンプル

// 依存関係: Node.js crypto モジュール
// https://nodejs.org/api/crypto.html#crypto_crypto
function sha256(buffer) {
    return crypto.createHash('sha256').update(buffer).digest();
}
var challenge = base64URLEncode(sha256(verifier));

Java サンプル

// 依存関係: Apache Commons Codec
// https://commons.apache.org/proper/commons-codec/
// Base64クラスをインポートします。
// import org.apache.commons.codec.binary.Base64;
byte[] bytes = verifier.getBytes("US-ASCII");
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(bytes, 0, bytes.length);
byte[] digest = md.digest();
String challenge = Base64.encodeBase64URLSafeString(digest);

Swift 5 のサンプル

import CommonCrypto

// ...

guard let data = verifier.data(using: .utf8) else { return nil }
var buffer = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
_ = data.withUnsafeBytes {
    CC_SHA256($0.baseAddress, CC_LONG(data.count), &buffer)
}
let hash = Data(buffer)
let challenge = hash.base64EncodedString()
    .replacingOccurrences(of: "+", with: "-")
    .replacingOccurrences(of: "/", with: "_")
    .replacingOccurrences(of: "=", with: "")

Objective-C の例

// 依存関係: Apple Common Crypto ライブラリ
// http://opensource.apple.com//source/CommonCrypto
u_int8_t buffer[CC_SHA256_DIGEST_LENGTH * sizeof(u_int8_t)];
memset(buffer, 0x0, CC_SHA256_DIGEST_LENGTH);
NSData *data = [verifier dataUsingEncoding:NSUTF8StringEncoding];
CC_SHA256([data bytes], (CC_LONG)[data length], buffer);
NSData *hash = [NSData dataWithBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
NSString *challenge = [[[[hash base64EncodedStringWithOptions:0]
                         stringByReplacingOccurrencesOfString:@"+" withString:@"-"]
                         stringByReplacingOccurrencesOfString:@"/" withString:@"_"]
                         stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]];

ユーザーを認可する

code_verifiercode_challenge を作成したら、ユーザーの認可を得る必要があります。技術的には、これは の始まりであり、このステップには次のプロセスのうち 1 つ以上が含まれる場合があります。
  • ユーザーを認証する。
  • 認証を処理するため、ユーザーを にリダイレクトする。
  • アクティブな シングルサインオン (SSO) セッションを確認する。
  • 以前に同意が与えられていない場合は、要求された権限レベルに対するユーザーの同意を取得する。
ユーザーを認可するには、アプリはユーザーを 認可 URL にリダイレクトする必要があります。その際、前のステップで生成した code_challenge と、code_challenge の生成に使用したメソッドを含めます。

認可 URL の例

パラメーター
カスタム API を呼び出す際にユーザーを認可する場合は、次の点に注意してください。
  • パラメーターを含める必要があります
  • 対象 API でサポートされている追加のスコープを含めることもできます
Parameter NameDescription
response_typeAuth0 が返す認証情報の種類 (code または token) を示します。このフローでは、値は code でなければなりません。
code_challengecode_verifier から生成されるチャレンジです。
code_challenge_methodチャレンジの生成に使用するメソッドです (例: S256) 。PKCE 仕様では S256plain の 2 つのメソッドが定義されています。この例では前者を使用しており、後者は非推奨のため、Auth0 でサポートされるのは S256 のみです。
client_idアプリケーションのクライアントIDです。この値は Application Settings で確認できます。
redirect_uriユーザーが認可を付与した後に、Auth0 がブラウザーをリダイレクトする先の URL です。認可コードは URL パラメーター code で受け取れます。この URL は、Application Settings で有効な callback URL として指定する必要があります。

警告: OAuth 2.0 Specification に従い、Auth0 はハッシュ以降のすべてを削除し、フラグメントは無視します。
scope認可をリクエストする スコープ です。各スコープはスペースで区切る必要があります。profileemail など、ユーザーに関する 標準 OpenID Connect (OIDC) スコープ名前空間形式 に準拠した カスタムクレーム、または対象 API でサポートされる任意のスコープ (例: read:contacts) をリクエストできます。リフレッシュトークン を取得するには offline_access を含めます (Application SettingsAllow Offline Access フィールドが有効になっていることを確認してください) 。
audienceモバイルアプリがアクセスする API の一意の識別子です。このチュートリアルの前提条件の一部として作成した API の Settings タブにある 識別子 の値を使用します。
state(推奨) アプリが最初のリクエストに追加する、不透明な任意の英数字文字列です。Auth0 はこれをアプリケーションへのリダイレクト時に含めます。この値を使用してクロスサイトリクエストフォージェリ (CSRF) 攻撃を防ぐ方法については、Mitigate CSRF Attacks With State Parameters を参照してください。
organization(任意) ユーザーの認証時に使用する組織の ID です。指定しない場合、アプリケーションで Display Organization Prompt が設定されていれば、ユーザーは認証時に組織名を入力できます。
invitation(任意) 組織への招待のチケット ID です。組織にメンバーを招待する 場合、ユーザーが招待を承諾したときに、アプリケーションは invitationorganization のキーと値のペアを転送して、招待の承諾を処理する必要があります。
例として、API を呼び出す際の認可 URL 用 HTML スニペットは次のようになります。

レスポンス

正常に処理されると、HTTP 302 レスポンスが返されます。認可コードは URL の末尾に含まれます。
HTTP/1.1 302 Found
Location: {yourCallbackUrl}?code={authorizationCode}&state=xyzABC123

トークンを要求する

認可コードを取得したら、それをトークンと交換する必要があります。前の手順で取得した認可コード (code) を使用し、code_verifier を含めて トークンURLPOST します。

トークンURLへのPOSTリクエストの例

パラメーター
パラメーター名説明
grant_type"authorization_code" に設定します。
code_verifierこのチュートリアルの最初のステップで生成した、暗号学的にランダムなキーです。
codeこのチュートリアルの前のステップで取得した authorization_code です。
client_idアプリケーションのクライアントIDです。この値は Application Settings で確認できます。
redirect_uriアプリケーション設定で設定した有効なコールバック URL です。これは、このチュートリアルの前のステップで認可 URL に渡した redirect_uri と完全に一致している必要があります。なお、URL エンコードする必要があります。

レスポンス

正常に処理されると、access_tokenrefresh_tokenid_tokentoken_type の各値を含むペイロードを含む HTTP 200 レスポンスが返されます。
{
  "access_token":"eyJz93a...k4laUWw",
  "refresh_token":"GEbRxBN...edjnXbL",
  "id_token":"eyJ0XAi...4faeEoQ",
  "token_type":"Bearer",
  "expires_in":86400
}
トークンは保存する前に検証してください。手順については、IDトークンを検証するおよびアクセストークンを検証するを参照してください。
IDトークンには、デコードして取り出す必要があるユーザー情報が含まれています。 アクセストークンは、Auth0 Authentication API の /userinfo エンドポイントまたは別の API を呼び出すために使用します。独自の API を呼び出す場合、最初に必要になるのは、アクセストークンを検証することです。 リフレッシュトークンは、前の または の有効期限が切れた後に、新しいトークンを取得するために使用します。refresh_token は、offline_access スコープを含め、Dashboard で API の Allow Offline Access を有効にした場合にのみレスポンスに含まれます。
リフレッシュトークンがあると、ユーザーは実質的に無期限で認証済みの状態を維持できるため、厳重に保管する必要があります。

API を呼び出す

ネイティブアプリケーションまたはモバイルアプリケーションから API を呼び出すには、アプリケーションで取得したアクセストークンを Bearer トークンとして HTTP リクエストの Authorization ヘッダーに渡す必要があります。

リフレッシュトークン

このチュートリアルに沿って進め、次の内容を完了していれば、すでにリフレッシュトークンを受け取っています。
  • API を設定してオフラインアクセスを許可した
  • authorize エンドポイントを通じて認証リクエストを開始する際に、offline_access スコープを含めた
新しいアクセストークンを取得するには、を使用できます。通常、ユーザーが新しいアクセストークンを必要とするのは、前のトークンの有効期限が切れた後か、新しいリソースへのアクセスが初めて必要になったときだけです。API を呼び出すたびに新しいアクセストークンを取得するためにこのエンドポイントを呼び出すのはベストプラクティスではありません。また、Auth0 ではレート制限が適用されているため、同じ IP から同じトークンを使用してそのエンドポイントに実行できるリクエスト数は制限されます。 トークンを更新するには、grant_type=refresh_token を使用して、Authentication API の /oauth/token エンドポイントに POST リクエストを送信します。

トークンURLへのPOSTの例

パラメーター
パラメーター名説明
grant_typerefresh_token に設定します。
client_idアプリケーションのクライアントIDです。この値は Application Settings で確認できます。
refresh_token使用するリフレッシュトークンです。
scope(任意) 要求するスコープをスペース区切りで指定します。指定しない場合は元のスコープが使用されます。指定した場合は、元のスコープより少ない範囲を要求できます。なお、URL エンコードが必要です。

レスポンス

正常に処理されると、新しい access_token、その有効期間 (秒単位、expires_in) 、付与された scope 値、token_type を含むペイロードとともに HTTP 200 レスポンスが返されます。初期トークンのスコープに openid が含まれている場合、レスポンスには新しい id_token も含まれます。
{
  "access_token": "eyJ...MoQ",
  "expires_in": 86400,
  "scope": "openid offline_access",
  "id_token": "eyJ...0NE",
  "token_type": "Bearer"
}
保存する前に、トークンを検証してください。方法については、IDトークンを検証するアクセストークンを検証する を参照してください。

使用例

トークンをカスタマイズする

Actions を使用すると、返されるアクセストークンのスコープを変更したり、アクセストークンやIDトークンにクレームを追加したりできます。 (Actions の詳細については、Auth0 Actions を参照してください。) これを行うには、ユーザーの認証後に実行される次の Action を追加します。
exports.onExecutePostLogin = async (event, api) => {
  // アクセストークンとIDトークンにカスタムクレームを追加する
  api.accessToken.setCustomClaim('https://foo/bar', 'value');
  api.idToken.setCustomClaim('https://fiz/baz', 'some other value');

  // アクセストークンのスコープを変更する
  api.accessToken.addScope('foo');
  api.accessToken.addScope('bar');
};
スコープは、Action の実行後にトークン内で利用できるようになります。
Auth0 は、OpenID Connect (OIDC) 仕様 で定義されているとおり、プロファイル情報を構造化されたクレーム形式で返します。つまり、IDトークンまたはアクセストークンに追加するカスタムクレームは、名前の衝突を避けるために、ガイドラインと制限事項 に準拠する必要があります。

サンプルアプリケーションを見る: モバイルアプリ + API

実装例については、アーキテクチャシナリオのモバイル + APIを参照してください。この一連のチュートリアルには、GitHubで参照できるコードサンプルも用意されています。

詳しく見る