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