بدء سريع: أي مكتبة OIDC
يُعد Usher مزوّد OpenID Connect قياسيًا. إذا كانت للغتك مكتبة عميل OIDC معتمدة، فلديك بالفعل كل ما تحتاجه: وجّهها إلى مستند الاكتشاف الخاص ببيئتك، واستخدم تدفق رمز التفويض مع PKCE.
الإعدادات
| الإعداد | القيمة |
|---|---|
| جهة الإصدار | https://<handle>.usherid.com |
| عنوان URL للاكتشاف | https://<handle>.usherid.com/.well-known/openid-configuration |
| التدفق | رمز التفويض (response_type=code) |
| PKCE | مطلوب، code_challenge_method=S256 |
| النطاقات | openid profile email offline_access |
| مصادقة العميل | كما هو مدرج في token_endpoint_auth_methods_supported |
تجد الاسم المختصر لبيئتك في Usher Console، بجانب جهة إصدارها. تحصل بيئات التطوير على اسم عشوائي، مثل wise-otter-42، أما بيئات الإنتاج فلها الاسم الذي اخترته. ويمكن لبيئة الإنتاج أن تقع على نطاقك الخاص بدلًا من ذلك، مثل login.acme.com، وعندها يكون هذا النطاق جهة إصدارها، بعد أن توجّهه إلى Usher بسجل CNAME.
اقرأ مستند الاكتشاف
كل نقطة نهاية ومفتاح يحتاجه عميلك مُدرج هنا. دع مكتبتك تقرأه بدلًا من نسخ عناوين URL إلى شيفرتك.
curl -s https://acme.usherid.com/.well-known/openid-configuration | jq{
"issuer": "https://acme.usherid.com",
"authorization_endpoint": "https://acme.usherid.com/api/auth/oauth2/authorize",
"token_endpoint": "https://acme.usherid.com/api/auth/oauth2/token",
"userinfo_endpoint": "https://acme.usherid.com/api/auth/oauth2/userinfo",
"jwks_uri": "https://acme.usherid.com/api/auth/jwks",
"introspection_endpoint": "https://acme.usherid.com/api/auth/oauth2/introspect",
"revocation_endpoint": "https://acme.usherid.com/api/auth/oauth2/revoke",
"end_session_endpoint": "https://acme.usherid.com/api/auth/oauth2/end-session",
"scopes_supported": ["openid", "profile", "email", "offline_access"],
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code", "refresh_token", "client_credentials"],
"code_challenge_methods_supported": ["S256"]
}التدفق
أرسل الشخص إلى نقطة نهاية التفويض
أنشئ مُحقِّق PKCE عشوائيًا واحفظه، مع قيمة state عشوائية، في مكان لا تصل إليه إلا جلسة هذا المتصفح (يفي ملف تعريف ارتباط قصير العمر من نوع httpOnly بالغرض). ثم أعد التوجيه مع response_type=code، و client_id و redirect_uri الخاصين بك، والنطاقات أعلاه، وقيمة state، و code_challenge المحسوب بطريقة S256 من المُحقِّق.
دعه يسجّل الدخول
يتولى Lobby الأمر من هنا: يذكر اسم تطبيقك، ويعرض طرق تسجيل الدخول التي تسمح بها بيئتك، ويطلب الموافقة في المرة الأولى.
تحقق من رد الاستدعاء
يعيد Usher التوجيه إلى redirect_uri الخاص بك مع code و state. ارفض الاستجابة ما لم تطابق state القيمة التي حفظتها. الرمز يُستخدم مرة واحدة ويبقى صالحًا خمس دقائق.
استبدل الرمز برموز مميزة
من خادمك، أرسل الرمز ومُحقِّق PKCE إلى نقطة نهاية الرموز المميزة:
curl -s -X POST https://acme.usherid.com/api/auth/oauth2/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d grant_type=authorization_code \
-d code="$CODE" \
-d redirect_uri=https://app.acme.example/callback \
-d code_verifier="$CODE_VERIFIER"تحقق من صحة رمز الهوية
تحقق من توقيعه مقابل المفاتيح الموجودة على jwks_uri، ومن أن iss هي جهة إصدارك، و aud هو معرّف العميل الخاص بك، و exp في المستقبل. تتولى مكتبتك ذلك نيابةً عنك، فتأكد من أنه غير معطَّل.
في Node.js
تتولى openid-client كل ما سبق، بما في ذلك التحقق من الصحة:
import * as client from 'openid-client'
// discovery: every endpoint and key comes from the issuer
const config = await client.discovery(
new URL('https://acme.usherid.com'),
process.env.USHER_CLIENT_ID!,
process.env.USHER_CLIENT_SECRET!,
)
// 1. send them to the Lobby, with PKCE (S256) and a state to check later
const codeVerifier = client.randomPKCECodeVerifier()
const state = client.randomState()
const url = client.buildAuthorizationUrl(config, {
redirect_uri: 'https://app.acme.example/callback',
scope: 'openid profile email offline_access',
code_challenge: await client.calculatePKCECodeChallenge(codeVerifier),
code_challenge_method: 'S256',
state,
})
// keep codeVerifier and state in a short-lived httpOnly cookie, then redirect to url
// 2. back at /callback: swap the code for tokens
const tokens = await client.authorizationCodeGrant(config, new URL(request.url), {
pkceCodeVerifier: codeVerifier,
expectedState: state,
})
const { sub, email, name } = tokens.claims()!في لغات أخرى
كل هذه المكتبات الواسعة الانتشار تتحدث بلغة OpenID Connect القياسية، وتعمل مع Usher دون أي شيء خاص به:
| اللغة | المكتبة |
|---|---|
| Python | Authlib |
| Go | coreos/go-oidc مع golang.org/x/oauth2 |
| Java | Spring Security OAuth 2.0 Client |
| .NET | Microsoft.AspNetCore.Authentication.OpenIdConnect |
| Ruby | omniauth_openid_connect |
| PHP | jumbojett/openid-connect-php |
البقاء مسجّل الدخول
مع النطاق offline_access، تتضمن استجابة الرموز المميزة رمز تحديث. استخدمه مع grant_type=refresh_token للحصول على رمز وصول جديد عند انتهاء صلاحية القديم. وتتجدد رموز التحديث: كل استخدام يُعيد رمزًا جديدًا، ويتوقف القديم عن العمل.
تسجيل الخروج
امسح جلستك أولًا، ثم أعد التوجيه إلى end_session_endpoint مع post_logout_redirect_uri (و id_token_hint إن كان لديك)، لكي ينسى Lobby الشخص أيضًا.