独自のAPI
アプリは、あなたのAPIのいずれかに対するアクセストークンを要求できます。受け取るのは、オーディエンスがそのAPIだけに限られた署名付きJWTで、APIはUsherを呼び出すことなく、環境が公開している鍵でそれを検証します。あるAPI向けのトークンは、別のAPIでは使えません。
APIに名前を付ける
Usher Consoleで環境を開き、アプリケーション → 独自のAPI → APIを追加を選びます。名前と識別子を付けてください。識別子は、https://api.example.comのようなhttps://のアドレスか、urn:example:api:notesのようなURNです。識別子は、アプリが要求する値であり、トークンのaudクレームに記される値でもあります(RFC 8707)。
次に、そのAPIを呼び出すアプリにAPIを割り当てます。各アプリケーションのAPIで設定します。アプリが何を要求しても、トークンを受け取れるのは割り当てられたAPIの分だけです。APIを削除すると、それ以降トークンは発行されず、すでに発行済みのトークンも数分以内に期限が切れます。
トークンを要求する
アプリは、認可リクエストとトークンリクエストにresource=<identifier>を追加します。モバイルSDKは、これを自動で行います。
let usher = UsherClient(configuration: .init(
issuer: URL(string: "https://login.example.com")!,
clientID: "…",
redirectURI: URL(string: "com.example.notes:/oauth/callback")!,
resources: ["urn:example:api:notes"]))
var request = URLRequest(url: URL(string: "https://api.example.com/notes")!)
try await usher.authorize(&request) // Authorization: Bearer <a JWT for the Notes API>val usher = Usher.client(context, UsherConfiguration(
issuer = "https://login.example.com",
clientId = "…",
redirectUri = "com.example.notes:/oauth/callback",
resources = listOf("urn:example:api:notes")))2つのAPIを呼び出すアプリは、両方を一度に要求できます。その場合、トークンのオーディエンスには両方が記されます。
APIで確認する
トークンの中身を信頼する前に、すべてのリクエストのトークンを確認してください。
- 署名:環境のディスカバリドキュメントにある
jwks_uriの鍵で検証します。アルゴリズムは鍵から取得し、決してトークンのヘッダーから取得しないでください。 iss:環境の発行者と完全に一致すること。この値は設定で固定し、決してトークンから読み取らないでください。aud:APIの識別子が含まれていること。(openidスコープを使う場合は、環境のuserinfoのアドレスも含まれます。)typ:ヘッダーの値がat+jwtであること。これにより、IDトークンをアクセストークンと偽って渡すことはできなくなります。exp:期限が過ぎていないこと。アクセストークンの有効期間は10分で、SDKが自動で更新します。
Node.jsでは、@usher/nodeがこのすべてを行います。
import { createVerifier } from '@usher/node'
const usher = await createVerifier({
issuer: 'https://login.example.com',
audience: 'urn:example:api:notes',
})
const claims = await usher.accessToken(bearerToken) // throws if any check failsASP.NET Coreでは、次のようにします。
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(o =>
{
o.Authority = "https://login.example.com"; // discovery and keys come from here
o.MapInboundClaims = false;
o.TokenValidationParameters = new()
{
ValidIssuer = "https://login.example.com",
ValidAudience = "urn:example:api:notes",
ValidTypes = ["at+jwt"],
};
});トークンの内容
| クレーム | |
|---|---|
sub | ユーザー。issと組み合わせて、そのユーザーを記録するためのキーになります。 |
client_id、azp | 要求したアプリ。 |
scope | アプリに許可することに、ユーザーが同意した内容。 |
email、email_verified | emailスコープを使う場合:ユーザーのアドレスと、それが本人のものであることをUsherが確認済みかどうか。 |
sid | ユーザーのサインインセッション。 |
org | organizationスコープを使う場合:ユーザーのアクティブな組織とロール。 |
既存のユーザー
APIに以前からのアカウントがある場合は、ユーザーがUsherのトークンを持って初めて来たときに、その人のアカウントを見つけられます。emailで検索します。ただし、email_verifiedがtrueの場合に限ります。そして、それ以降はissとsubをそのアカウントに保存しておきます。以後は、メールアドレスではなく、必ずissとsubでユーザーを見つけてください。メールアドレスは持ち主が変わることがありますが、サブジェクトは決して変わりません。