דילוג לתוכן
תיעוד · ממשקי ה-API שלך

ממשקי ה-API שלך

אפליקציה יכולה לבקש אסימון גישה לאחד מממשקי ה-API שלך. היא מקבלת JWT חתום שהקהל שלו הוא ה-API הזה ותו לא, וה-API שלך בודק אותו עם המפתחות שהסביבה שלך מפרסמת, בלי לפנות ל-Usher. אסימון של API אחד לא שווה כלום ב-API אחר.

מתן שם ל-API

ב-Usher Console, פותחים את הסביבה ועוברים אל אפליקציות ← ממשקי ה-API שלך ← הוספת API. נותנים לו שם ומזהה: כתובת https://, כמו https://api.example.com, או URN, כמו urn:example:api:notes. המזהה הוא מה שהאפליקציה מבקשת, ומה שמופיע ב-claim aud של האסימון (RFC 8707).

אחר כך נותנים את ה-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")))

אפליקציה שקוראת לשניים מממשקי ה-API שלך יכולה לבקש את שניהם בבת אחת; הקהל של האסימון יכלול אז את שניהם.

בדיקת האסימון ב-API שלך

יש לבדוק את האסימון של כל בקשה לפני שסומכים על משהו שבתוכו:

  • החתימה, מול המפתחות ב-jwks_uri שבמסמך הגילוי של הסביבה שלך. את האלגוריתם לוקחים מהמפתח, ואף פעם לא מהכותרת של האסימון.
  • iss הוא בדיוק המנפיק של הסביבה שלך. קובעים אותו בהגדרות שלך, ואף פעם לא קוראים אותו מהאסימון.
  • aud כולל את המזהה של ה-API שלך. (עם ה-scope openid הוא כולל גם את כתובת ה-userinfo של הסביבה.)
  • typ בכותרת הוא at+jwt, כך שאי אפשר להעביר אסימון זהות כאילו היה אסימון גישה.
  • 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"],
        };
    });

מה האסימון אומר

Claim
subהאדם. יחד עם iss, זה המפתח לזהות אותו לאורך זמן.
client_id, azpהאפליקציה שביקשה.
scopeמה שהאדם הסכים שהאפליקציה תוכל לעשות.
email, email_verifiedעם ה-scope email: הכתובת של האדם, והאם Usher הוכיח שהיא שלו.
sidסשן ההתחברות שלו.
orgעם ה-scope organization: הארגון הפעיל שלו והתפקיד שלו בו.

אנשים שכבר מכירים

אם ל-API שלך כבר יש חשבונות מלפני כן, אפשר למצוא את החשבון של אדם בפעם הראשונה שהוא מגיע עם אסימון של Usher: מחפשים אותו לפי email, רק כש-email_verified הוא true, ומאז שומרים את iss ו-sub בחשבון שלו. מכאן והלאה מחפשים אותו לפי iss ו-sub, ואף פעם לא לפי כתובת הדוא״ל: כתובת יכולה לעבור לידיים אחרות, ומזהה (subject) אף פעם לא.