跳到正文
文档 · 你自己的 API

你自己的 API

App 可以请求访问你某个 API 的访问令牌。它会得到一个已签名的 JWT,其受众只有这个 API,你的 API 用环境公布的密钥即可校验,无需调用 Usher。用于一个 API 的令牌,拿到另一个 API 上毫无用处。

为 API 命名

在 Usher Console 中打开环境,然后前往 应用 → 你的 API → 添加 API。为它填写名称和标识符:标识符可以是一个 https:// 地址,例如 https://api.example.com,也可以是一个 URN,例如 urn:example:api:notes。标识符既是 App 请求的内容,也是令牌 aud 声明中写明的值(RFC 8707)。

然后把这个 API 分配给调用它的 App:在每个应用的 API 中设置。无论 App 请求什么,它都只能获得已分配给它的 API 的令牌。移除某个 API 后,它就不会再获得新的令牌;已经签发出去的令牌会在几分钟内过期。

请求令牌

App 在授权请求和令牌请求中加上 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")))

如果 App 要调用你的两个 API,可以同时请求两者;这时令牌的受众会同时列出这两个 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发出请求的 App。
scope用户同意该 App 可以做的事情。
email、email_verified使用 email 范围时提供:用户的电子邮件地址,以及 Usher 是否已证实该地址属于此人。
sid用户的登录会话。
org使用 organization 范围时提供:用户当前所在的组织及其角色。

你已经认识的用户

如果你的 API 中已经有以前的账户,那么当某人第一次带着 Usher 令牌到来时,你可以找到他的账户:按 email 查找,但仅限 email_verified 为 true 的情况,并从那以后在他的账户上保存 iss 和 sub。此后,请按 iss 和 sub 查找,绝不要按电子邮件地址查找:电子邮件地址可能易主,而主体标识(subject)永远不会变。