本文へ移動
ドキュメント · 独自のAPI

独自の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は、これを自動で行います。

swift
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>
kotlin
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がこのすべてを行います。

TypeScript
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 fails

ASP.NET Coreでは、次のようにします。

csharp
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_verifiedemailスコープを使う場合:ユーザーのアドレスと、それが本人のものであることをUsherが確認済みかどうか。
sidユーザーのサインインセッション。
orgorganizationスコープを使う場合:ユーザーのアクティブな組織とロール。

既存のユーザー

APIに以前からのアカウントがある場合は、ユーザーがUsherのトークンを持って初めて来たときに、その人のアカウントを見つけられます。emailで検索します。ただし、email_verifiedがtrueの場合に限ります。そして、それ以降はissとsubをそのアカウントに保存しておきます。以後は、メールアドレスではなく、必ずissとsubでユーザーを見つけてください。メールアドレスは持ち主が変わることがありますが、サブジェクトは決して変わりません。