Բոլոր դասերը
ԱնվտանգությունԱռաջադեմ14 րոպե ընթերցումԻմ ստեկում

OAuth 2.x և OpenID Connect

Պատվիրակված հասանելիություն և «Sign in with…»՝ PKCE-ով, կարճաժամկետ token-ներով և ճիշտ scope-ներով։

  • OAuth 2.1
  • OIDC
  • PKCE
  • Tokens
  • Scopes
Քայլ 1/6
Դու սեղմում ես «Sign in with ID» app.com-ում։ Հավելվածը քո գաղտնաբառը տեսնել չի ուզում. OAuth-ի ամբողջ իմաստը հենց դա է։

30 վայրկյանում

OAuth-ը թույլ է տալիս հավելվածին գործել օգտատիրոջ անունից՝ առանց երբևէ նրա գաղտնաբառը տեսնելու․ օգտատերը հասանելիությունը հաստատում է authorization server-ում, և հավելվածը ստանում է սահմանափակ, ժամկետով access token։ OpenID Connect-ը վերևում ավելացնում է ինքնությունը, ուստի հավելվածը նաև իմանում է, թե ով է օգտատերը․ հենց դա է աշխատեցնում «Sign in with Google»-ը կամ Apple-ը։ Ժամանակակից բաղադրատոմսը authorization code flow-ն է PKCE-ով՝ յուրաքանչյուր client-ի համար։

Ինչու եմ օգտագործում

  • OAuth օգտագործում եմ, որովհետև իմ կառուցած գրեթե յուրաքանչյուր API սպասարկում է մի քանի client՝ վեբ, մոբայլ, admin, և scope-ներով ու ժամկետով token-ները դրանց authentication-ի ամենամաքուր եղանակն են՝ առանց գաղտնաբառեր փոխանցելու։
  • Սպառողական պրոդուկտներում օգտագործում եմ social sign-in (Google, Apple, LinkedIn, Facebook), որովհետև այն վերացնում է գրանցման դժվարությունը, իսկ OpenID Connect-ը այն ստանդարտն է, որը դա անվտանգ է դարձնում, եթե ճիշտ է ստուգվում։
  • Ինձ համար կարևոր են մանրամասները՝ PKCE, token-ների կյանքի տևողություն, revocation, scope-ներ, որովհետև authentication-ի բագերը հենց նրանք են, որոնք արտահոսեցնում են հաշիվները, իսկ դիզայնի փուլում դրանք կանխելը էժան է։
  • Specification-ների իմացությունը թույլ է տալիս յուրաքանչյուր նախագծի համար իմաստուն ընտրություն անել Laravel Passport-ի, Sanctum-ի, managed identity provider-ի կամ custom JWT-ների միջև՝ մեկ գործիքի վրա default-ով կանգ առնելու փոխարեն։

Ինչպես է աշխատում

01Գաղափարը՝ valet բանալի, ոչ թե ձեր տան բանալին

Որոշ մեքենաներ գալիս են valet բանալիով․ այն միացնում է շարժիչը, բայց չի կարող բացել բեռնախցիկը։ OAuth-ը հավելվածներին տալիս է valet բանալիներ։ Ներգրավված են չորս դեր։ Resource owner-ը օգտատերն է։ Client-ը հավելվածն է, որն ուզում է հասանելիություն։ Authorization server-ը authenticate է անում օգտատիրոջը և թողարկում token-ներ։ Resource server-ը API-ն է, որն ընդունում է token-ները։ Օգտատերը մուտք է գործում միայն authorization server-ում և հաստատում կոնկրետ scope-ներ՝ «կարդալ ձեր օրացույցը», և client-ը ստանում է access token՝ վավեր այդ scope-ների և սահմանափակ ժամանակի համար։ Client-ը երբեք չի տեսնում գաղտնաբառը։ Կարևոր տարբերակում՝ OAuth 2.0-ը authorization-ի մասին է (ինչ կարող է անել հավելվածը), ոչ թե authentication-ի (ով է օգտատերը)։ Պարզ OAuth access token-ը որպես ինքնության ապացույց օգտագործելը դասական սխալ է, և հենց այդ բացն է լրացնում OpenID Connect-ը։

  • Resource owner՝ օգտատերը
  • Client՝ վեբ, մոբայլ կամ սերվերային հավելված
  • Authorization server՝ մուտք է գործացնում օգտատիրոջը, թողարկում token-ներ
  • Resource server՝ ձեր API-ն, ստուգում է token-ները

02Authorization code flow PKCE-ով՝ քայլ առ քայլ

Սա առաջարկվող flow-ն է վեբ հավելվածների, SPA-ների և մոբայլ հավելվածների համար։ Client-ը ստեղծում է պատահական code_verifier և authorization հարցման մեջ ուղարկում դրա SHA-256 hash-ը (code_challenge)։ Օգտատերը մուտք է գործում և համաձայնություն տալիս, և server-ը redirect է անում հետ՝ միանգամյա authorization code-ով։ Client-ը back channel-ով code-ը գումարած սկզբնական verifier-ը փոխանակում է token-ների հետ։ PKCE-ն (Proof Key for Code Exchange, RFC 7636) նշանակում է, որ գողացված code-ն անօգուտ է առանց verifier-ի, որը երբեք չի լքել հավելվածը։ State պարամետրը պաշտպանում է redirect-ի ժամանակ CSRF-ից, իսկ OIDC-ի դեպքում nonce-ը ID token-ը կապում է այս մուտքի հետ։ Redirect URI-ները պետք է գրանցված լինեն և ճշգրիտ համընկնեն։ OAuth 2.1-ը, որը 2026-ի վերջին դեռ IETF draft է, բայց արդեն արտացոլված է RFC 9700-ում (OAuth 2.0 Security Best Current Practice), պահանջում է PKCE բոլոր client-ների համար և հանում implicit և password grant-երը։

http
# 1) Browser is redirected to the authorisation server
GET https://auth.example.com/authorize?response_type=code
  &client_id=web-app
  &redirect_uri=https://app.example.com/callback
  &scope=openid%20profile%20email%20orders:read
  &state=af0ifjsldkj&nonce=n-0S6_WzA2Mj
  &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
  &code_challenge_method=S256
 
# 2) Back channel: exchange the code for tokens
POST https://auth.example.com/token
Content-Type: application/x-www-form-urlencoded
 
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https://app.example.com/callback
&client_id=web-app&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

03Token-ներ՝ access, refresh և ID token-ներ

Access token-ը այն է, ինչ client-ն ուղարկում է API-ին, սովորաբար որպես «Authorization: Bearer ...»։ Այն պետք է լինի կարճաժամկետ՝ րոպեներ, ոչ թե ամիսներ, որովհետև bearer token ունեցող ցանկացած մեկը կարող է օգտագործել այն։ Այն կարող է լինել opaque (API-ն այն ստուգում է authorization server-ի հետ introspection-ով) կամ JWT (API-ն ստորագրությունը ստուգում է լոկալ)։ Refresh token-ը թույլ է տալիս client-ին նոր access token-ներ ստանալ՝ առանց օգտատիրոջ նորից մուտք գործելու․ այն երկարաժամկետ է և հզոր, ուստի պահեք զգույշ, rotate արեք յուրաքանչյուր օգտագործման ժամանակ և revoke արեք logout-ի ժամանակ։ ID token-ը՝ OpenID Connect-ից, ստորագրված JWT է, որը client-ին ասում է, թե ով է մուտք գործել՝ issuer (iss), subject id (sub), audience (aud), expiry (exp), nonce և ըստ ցանկության email կամ անուն։ ID token-ը client-ի կարդալու համար է․ այն նախատեսված չէ ձեր API-ներին որպես access token ուղարկելու համար։

  • Access token՝ API-ի համար, կարճաժամկետ, scope-ներով
  • Refresh token՝ client-ի համար՝ հասանելիությունը թարմացնելու, rotate և revoke արեք
  • ID token՝ client-ի համար, ապացուցում է, թե ով է մուտք գործել

04OpenID Connect՝ «Sign in with Google / Apple»

OpenID Connect-ը (OIDC) բարակ ինքնության շերտ է OAuth 2.0-ի վրա։ Ավելացնում եք «openid» scope-ը, և authorization server-ը access token-ի կողքին վերադարձնում է ID token։ Provider-ները /.well-known/openid-configuration հասցեում հրապարակում են discovery փաստաթուղթ, որտեղ թվարկված են իրենց endpoint-ները և JWKS URL-ը՝ ստորագրման բանալիներով։ Օգտատիրոջն անվտանգ մուտք գործացնելու համար ձեր բեքենդը պետք է ստուգի ID token-ը՝ ստորագրությունը provider-ի ընթացիկ բանալիով, iss-ը հավասար է provider-ին, aud-ը հավասար է ձեր client id-ին, exp-ը չի անցել, և nonce-ը համընկնում է ձեր ուղարկածին։ Հետո հաշիվը կապեք provider-ի կայուն sub-ով, ոչ թե email-ով, որովհետև email-ները փոխվում են և միշտ չէ, որ ստուգված են։ Մոբայլում native SDK-ները (Google Sign-In, Sign in with Apple) վերադարձնում են ID token կամ authorization code, որը հավելվածն ուղարկում է ձեր բեքենդին նույն ստուգման համար՝ նախքան ձեր սեփական session-ը կամ API token-ները թողարկելը։

php
use Laravel\Socialite\Facades\Socialite;
 
// Redirect the user to Google
Route::get('/auth/google', fn () => Socialite::driver('google')->redirect());
 
// Callback: Socialite exchanges the code and fetches the profile
Route::get('/auth/google/callback', function () {
    $g = Socialite::driver('google')->user();
 
    $user = User::firstOrCreate(
        ['google_id' => $g->getId()],          // stable provider "sub"
        ['name' => $g->getName(), 'email' => $g->getEmail()],
    );
    Auth::login($user);
    return redirect('/account');
});

05Այլ grant-եր և API key-եր

Ոչ բոլոր client-ներն ունեն օգտատեր բրաուզերում։ Client credentials՝ բեքենդ ծառայությունը authenticate է անում ինքն իրեն (client id և secret, կամ ավելի լավ՝ ստորագրված assertion կամ mutual TLS)՝ մեկ այլ ծառայություն կանչելու համար՝ machine-to-machine։ Device authorization (RFC 8628)՝ smart TV-ները և CLI-ները ցույց են տալիս կոդ, որը օգտատերը մուտքագրում է իր հեռախոսում։ Token exchange (RFC 8693)՝ ծառայությունը մի token-ը փոխանակում է մեկ այլի հետ՝ ավելի նեղ scope-ով կամ այլ audience-ով։ Refresh token grant՝ թարմացնել հասանելիությունը։ Հնացած՝ implicit grant-ը (token-ները URL fragment-ում) և resource owner password grant-ը (հավելվածը հավաքում է օգտատիրոջ գաղտնաբառը), երկուսն էլ հանված են OAuth 2.1-ում։ Պարզ API key-երը դեռ տարածված են server-to-server ինտեգրացիաների համար․ եթե օգտագործում եք դրանք, դարձրեք scope-ներով, միջավայրով prefix-ված (live/test), պահոցում hash արված, rate-limit արված և rotate արվող՝ առանց downtime-ի։

06Laravel Passport-ը գործնականում

Laravel Passport-ը լիարժեք OAuth2 server է Laravel API-ների համար՝ կառուցված League OAuth2 server-ի վրա։ Ընթացիկ տարբերակներն աջակցում են authorization code grant-ը (PKCE-ով public client-ների համար), client credentials, device authorization, refresh token-ներ և personal access token-ներ․ password և implicit grant-երն անջատված են, եթե բացահայտ չեք միացնում։ Scope-ները սահմանում եք Passport::tokensCan-ով, route-երը պաշտպանում auth:api guard-ով գումարած scope middleware, իսկ token-ների կյանքի տևողությունը դնում service provider-ում․ default-ով access token-ները ապրում են մեկ տարի, ինչը հավելվածների մեծ մասի համար չափազանց երկար է, ուստի կրճատեք։ Նույն դոմենի վրա first-party SPA-ների համար Laravel Sanctum-ի cookie-ի վրա հիմնված session-ները հաճախ ավելի պարզ են, քան OAuth-ը․ Passport-ը փայլում է, երբ ձեզ պետք են իրական OAuth client-ներ, երրորդ կողմի հասանելիություն կամ token-ի վրա հիմնված մոբայլ հավելվածներ։

php
// AppServiceProvider::boot()
use Carbon\CarbonInterval;
use Laravel\Passport\Passport;
 
Passport::tokensCan([
    'orders:read'   => 'View your orders',
    'orders:create' => 'Place orders',
]);
Passport::tokensExpireIn(CarbonInterval::minutes(30));
Passport::refreshTokensExpireIn(CarbonInterval::days(30));
 
// routes/api.php
use Laravel\Passport\Http\Middleware\CheckToken;
 
Route::get('/orders', [OrderController::class, 'index'])
    ->middleware(['auth:api', CheckToken::using('orders:read')]);

Օգտագործեք, երբ

  • API, որն օգտագործում են մի քանի first-party client-ներ (վեբ, մոբայլ, admin), որոնց պետք են scope-ներով, ժամկետով token-ներ։
  • Երրորդ կողմի հավելվածներին կամ գործընկերներին թույլ տալ մուտք գործել օգտատիրոջ տվյալներին՝ օգտատիրոջ համաձայնությամբ։
  • Social կամ enterprise sign-in (Google, Apple, Microsoft, LinkedIn, կորպորատիվ SSO) OpenID Connect-ի միջոցով։
  • Machine-to-machine կանչեր ծառայությունների միջև՝ client credentials grant-ով։

Մի՛ օգտագործեք, երբ

  • Մեկ first-party վեբ հավելված մեկ դոմենի վրա․ անվտանգ HTTP-only session cookie-ները (օրինակ՝ Laravel Sanctum-ի SPA ռեժիմը) ավելի պարզ են և նույնքան անվտանգ։
  • Ներքին script-ներ, որոնց պետք է միայն նեղ, revoke արվող API key, որտեղ լիարժեք OAuth server-ը բարդություն է ավելացնում՝ առանց օգուտի։
  • Երբ պատրաստվում եք ձեր սեփական OAuth server-ը գրել զրոյից․ փոխարենը օգտագործեք սպասարկվող գրադարան կամ identity provider։

Այլընտրանքներ

  • Session cookie-ներ

    Դասական server session-ներ HttpOnly, Secure, SameSite cookie-ներով․ իդեալական են same-site վեբ հավելվածների համար։

  • Laravel Sanctum

    Թեթև SPA cookie auth և պարզ personal API token-ներ Laravel-ի համար՝ առանց լիարժեք OAuth flow-երի։

  • Managed identity provider-ներ

    Auth0, Okta, Microsoft Entra ID, AWS Cognito, Keycloak (self-hosted)՝ OAuth/OIDC, MFA և SSO որպես ծառայություն։

  • SAML 2.0

    Ավելի հին XML-ի վրա հիմնված enterprise SSO ստանդարտ, որը դեռ պահանջում են որոշ կորպորատիվ հաճախորդներ։

Լավագույն պրակտիկաներ

  1. Յուրաքանչյուր client-ի համար, ներառյալ confidential վեբ հավելվածները, օգտագործեք authorization code flow PKCE-ով (S256)։
  2. Գրանցեք ճշգրիտ redirect URI-ներ․ երբեք մի թույլատրեք wildcard-ներ կամ open redirect-ներ։
  3. Access token-ները պահեք կարճաժամկետ (րոպեներ), refresh token-ները rotate արեք օգտագործման ժամանակ և revoke արեք logout-ի և գաղտնաբառի փոփոխության ժամանակ։
  4. JWT-ները ստուգեք ամբողջությամբ՝ ստորագրությունը allow-list-ում գտնվող ալգորիթմով, iss, aud, exp, nbf, իսկ ID token-ների համար՝ նաև nonce։
  5. Scope-ները նախագծեք բիզնես հնարավորությունների շուրջ (orders:read) և ստուգեք դրանք յուրաքանչյուր endpoint-ում՝ գումարած object-level authorization։
  6. Social հաշիվները կապեք provider-ի sub claim-ով, ոչ թե միայն email-ով։
  7. Token-ները պահեք անվտանգ՝ վեբում HttpOnly cookie-ներ կամ backend-for-frontend, մոբայլում Keychain/Keystore, երբեք localStorage երկարաժամկետ token-ների համար։

Տարածված սխալներ

  • OAuth access token-ը որպես մուտքի ապացույց օգտագործել առանց OIDC ստուգման, կամ ընդունել այլ հավելվածի համար թողարկված ID token-ներ (aud-ի ստուգում չկա)։
  • Ընդունել alg «none»-ով JWT-ներ կամ թույլ տալ token-ի header-ին ընտրել ալգորիթմը։
  • Մեկ տարի ապրող access token-ներ՝ առանց revocation-ի ճանապարհի։
  • Բաց թողնել state պարամետրը՝ թույլ տալով login CSRF callback-ում։
  • Client secret-ը ներդնել մոբայլ հավելվածի կամ SPA-ի bundle-ում, որտեղից ցանկացած մեկը կարող է այն հանել։

Խորը վերլուծություն

07JWT-ների ճիշտ ստուգում (և դասական հարձակումները)

JWT-ն header.payload.signature է՝ base64url-encoded։ Ստուգումը պետք է լինի խիստ։ Սպասվող ալգորիթմը pin արեք ձեր կոդում (օրինակ՝ RS256 կամ ES256) և մերժեք ամեն այլ բան․ պատմական խոցելիությունները գալիս էին գրադարաններից, որոնք վստահում էին header-ի alg-ին՝ թույլ տալով «none» կամ HS256-ի և public key-ի շփոթություն։ Ստորագրման բանալիները ստացեք issuer-ի JWKS endpoint-ից, քեշավորեք, ընտրեք ըստ kid-ի և թարմացրեք անհայտ kid-ի դեպքում՝ key rotation-ն աջակցելու համար։ Ստուգեք iss-ը և aud-ը ճշգրիտ, exp-ը և nbf-ը՝ ժամացույցի փոքր շեղման թույլտվությամբ, իսկ ID token-ների համար՝ nonce-ը։ Զգայուն տվյալներ մի դրեք payload-ում․ այն ստորագրված է, ոչ թե գաղտնագրված։ RFC 8725-ը (JWT Best Current Practices) հղումային փաստաթուղթն է։ Նախընտրեք ասիմետրիկ ստորագրում, որպեսզի resource server-ները պահեն միայն public key-եր, և միայն authorization server-ը կարողանա token-ներ ստեղծել։

ts
import { createRemoteJWKSet, jwtVerify } from "jose";
 
const JWKS = createRemoteJWKSet(new URL("https://auth.example.com/.well-known/jwks.json"));
 
export async function verifyAccessToken(token: string) {
  const { payload } = await jwtVerify(token, JWKS, {
    issuer: "https://auth.example.com",
    audience: "https://api.example.com",
    algorithms: ["RS256"],      // never trust the header's alg
    clockTolerance: 30,         // seconds
  });
  if (await denylist.has(payload.jti as string)) throw new Error("revoked");
  return payload; // sub, scope, exp, ...
}

08Refresh token rotation և reuse detection

Refresh token-ները թագի գոհարներն են՝ երկարաժամկետ և ունակ access token-ներ ստեղծելու։ Rotation-ը նշանակում է, որ յուրաքանչյուր refresh վերադարձնում է նոր refresh token և անվավեր դարձնում հինը։ Reuse detection-ը ավելացնում է անվտանգության հիմնական հատկությունը․ եթե հին, արդեն օգտագործված refresh token-ը նորից է ներկայացվում, կամ օրինական client-ը, կամ հարձակվողն ունի գողացված պատճեն, ուստի server-ը revoke է անում ամբողջ token ընտանիքը և ստիպում նորից մուտք գործել։ Իրականացրեք սա՝ յուրաքանչյուր refresh token-ի համար պահելով family id և used դրոշ։ Ավելացրեք բացարձակ կյանքի տևողություն (օրինակ՝ 30–90 օր) և idle timeout, որպեսզի լքված session-ները մահանան։ Մշակեք race-երը մոբայլ հավելվածներում, որտեղ երկու զուգահեռ հարցում միաժամանակ փորձում են refresh անել՝ client-ում refresh-ները սերիալիզացրեք կամ նախորդ token-ի համար թույլ տվեք շատ կարճ grace window։ Sender-constrained token-ներն ավելի հեռու են գնում՝ token-ները կապելով client-ի բանալու հետ, որպեսզի գողացված token-ը չկարողանա replay արվել այլ տեղում։

09Sender-constrained token-ներ՝ DPoP և mTLS

Bearer token-ները աշխատում են կանխիկի պես՝ ով պահում է, նա էլ կարող է ծախսել։ Sender-constrained token-ները աշխատում են PIN-ով քարտի պես։ DPoP-ի (RFC 9449) դեպքում client-ը գեներացնում է key pair, և յուրաքանչյուր հարցման հետ ուղարկում կարճ ստորագրված proof JWT, որը պարունակում է HTTP method-ը, URL-ը, timestamp և access token-ի hash։ Authorization server-ը token-ը կապում է client-ի public key-ի հետ (cnf claim), իսկ API-ն ստուգում է, որ յուրաքանչյուր հարցում ստորագրված է նույն բանալիով։ Log-երի կամ proxy-ի միջոցով արտահոսած token-ը դառնում է անօգուտ։ Mutual TLS-ը (RFC 8705) նույնին հասնում է՝ token-ները կապելով client certificate-ի հետ, ինչը տարածված է բանկային և open-finance պրոֆիլներում, ինչպիսին է FAPI 2.0-ը։ Pushed Authorization Requests-ը (PAR, RFC 9126) լրացնում է սա՝ authorization պարամետրերը ուղարկելով back channel-ով՝ բրաուզերի URL-ի փոխարեն, ինչը կանխում է կեղծումը։

http
POST /orders HTTP/1.1
Host: api.example.com
Authorization: DPoP eyJhbGciOiJFUzI1NiIsImtpZCI6IjEifQ...
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Li4ufX0...
 
# DPoP proof payload (signed with the client's private key):
# { "htm": "POST", "htu": "https://api.example.com/orders",
#   "iat": 1793000000, "jti": "e1j3V_bKic8-LAEB", "ath": "<sha256 of access token>" }

10Multi-tenant և B2B ինքնության դիզայն

SaaS-ում ինքնությունն ավելի բարդ է դառնում․ օգտատերերը պատկանում են կազմակերպությունների, կարող են պատկանել մի քանիսին, իսկ enterprise հաճախորդներն ուզում են իրենց սեփական SSO-ն։ Tenant-ը token-ի մեջ դրեք միտումնավոր՝ tenant կամ org claim, որն ընտրվում է մուտքի ժամանակ կամ կազմակերպության switcher-ով, և յուրաքանչյուր հարցման ժամանակ ստուգեք, որ resource-ը պատկանում է այդ tenant-ին․ երբեք tenant id-ները մի վերցրեք միայն հարցման body-ից։ Role-երը և իրավունքները պահեք ձեր հավելվածում՝ անհրաժեշտության դեպքում mapping անելով IdP խմբերից, այլ ոչ թե վստահելով արտաքին IdP-ների կամայական claim-երին։ Enterprise SSO-ի համար աջակցեք յուրաքանչյուր tenant-ի OIDC կամ SAML կապերը, գումարած SCIM օգտատերերի provisioning-ի համար, եթե հաճախորդները խնդրում են։ Պլանավորեք impersonation-ը․ support-ի անձնակազմը պետք է ստանա առանձին, ժամանակով սահմանափակված token՝ act (actor) claim-ով, պարտադիր պատճառով և ամբողջական audit logging-ով, երբեք հաճախորդի սեփական credentials-ը։

Իրական իրավիճակներ

01

Sign in with Apple-ի ավելացում մոբայլ հավելվածին

Խնդիր

React Native հավելվածն արդեն ունի email-ով և գաղտնաբառով մուտք։ Թիմը պետք է ավելացնի Sign in with Apple և Google, և ուզում է, որ հաշիվները ճիշտ կապվեն, երբ նույն մարդը օգտագործում է մի քանի եղանակ։

Ինչպես լուծել

Սարքի վրա օգտագործեք native SDK-ները՝ ID token կամ authorization code ստանալու համար, հետո ուղարկեք այն բեքենդին։ Բեքենդը ստուգում է ID token-ի ստորագրությունը provider-ի JWKS-ի դեմ, գումարած iss, aud՝ հավասար ձեր հավելվածի client id-ին, exp և nonce։ Պահեք առանձին identities աղյուսակ (provider, sub, user_id) և կապեք ըստ sub-ի։ Apple-ը կարող է իրական email-ը թաքցնել relay հասցեի հետևում և անունն ուղարկում է միայն առաջին մուտքի ժամանակ, ուստի պահեք այն այդ պահին։ Գոյություն ունեցող հաշվին email-ով կապեք միայն այն դեպքում, երբ provider-ը նշում է այն որպես verified, և օգտատերը հաստատում է։ Վերջապես, թողարկեք ձեր սեփական կարճաժամկետ API token-ը գումարած refresh token։

02

Արտահոսած access token log-երում

Խնդիր

Անվտանգության ստուգումը հավելվածի log-երում գտնում է ամբողջական Authorization header-ներ։ Access token-ները վավեր են մեկ տարի, և որոշ log-եր կիսվել են vendor-ի հետ։

Ինչպես լուծել

Վերաբերվեք դրան որպես incident-ի։ Revoke արեք ուղղումից առաջ թողարկված բոլոր access և refresh token-ները՝ ստիպելով նորից մուտք գործել, և rotate արեք ցանկացած client secret, որը նույնպես կարող էր արտահոսել։ Հեռացրեք header-ները log-երից՝ ավելացրեք redaction logging middleware-ում և proxy-ներում և հնարավորության դեպքում մաքրեք հին log տվյալները։ Access token-ի կյանքը կրճատեք մինչև 15–30 րոպե և միացրեք refresh token rotation։ Ավելացրեք denylist-ի ստուգում ըստ jti-ի՝ շտապ revocation-ի համար։ Ավելացրեք թեստ, որը ձախողվում է, եթե Authorization header-ները հայտնվում են log-ի ելքում, և փաստագրեք token-ի կյանքի տևողության քաղաքականությունը։

03

Գործընկերների API հասանելիություն

Խնդիր

Գործընկերներն ուզում են ձեր API-ով պատվերներ ստեղծել իրենց սեփական server-ներից։ Որոշ գործընկերներ ինտեգրվում են բազմաթիվ merchant-ների անունից, մյուսներին պետք է միայն հաշվետվությունների կարդալու հասանելիություն։

Ինչպես լուծել

Առաջարկեք client credentials grant կամ scope-ներով API key-եր, եթե գործընկերներին պարզություն է պետք։ Յուրաքանչյուր գործընկեր ստանում է առանձին test և live credentials՝ orders:create կամ reports:read տիպի scope-ներով և rate limit-ներով յուրաքանչյուր client-ի համար։ Credentials-ը կապեք այն tenant-ի կամ merchant-ների հետ, որոնց անունից գործընկերը կարող է գործել, և կիրառեք դա server-side։ Պատվերի ստեղծման համար պահանջեք idempotency key-եր, որպեսզի retry-ները երբեք չկրկնօրինակեն պատվերները։ Աջակցեք համընկնող բանալիներ zero-downtime rotation-ի համար, log արեք օգտագործումն ըստ client-ի և գործընկերներին տվեք dashboard՝ revoke և վերագեներացնելու համար։ Բարձր արժեք ունեցող գործընկերների համար shared secret-ների փոխարեն օգտագործեք ստորագրված JWT client assertion-ներ։

Արագ ուղեցույց

Առաջարկվող flow ցանկացած հավելվածի համար
Authorization code + PKCE (code_challenge_method=S256)
OIDC discovery փաստաթուղթ
GET https://auth.example.com/.well-known/openid-configuration
Ստեղծել PKCE challenge (bash)
printf %s "$VERIFIER" | openssl dgst -sha256 -binary | base64 | tr '+/' '-_' | tr -d '='
Տեղադրել Passport-ը (Laravel)
php artisan install:api --passport
Ստեղծել PKCE (public) client Passport-ում
php artisan passport:client --public
Կարճ Passport access token-ներ
Passport::tokensExpireIn(CarbonInterval::minutes(30));
Պահանջել scope route-ի վրա
->middleware(['auth:api', CheckToken::using('orders:read')])
Revoke անել token (RFC 7009)
POST /revoke token=...&token_type_hint=refresh_token
ID token-ի վրա ստուգվող claim-եր
signature, iss, aud, exp, iat, nonce — հետո կապել ըստ sub-ի
Machine-to-machine
grant_type=client_credentials&scope=reports:read

Իմ իրական նախագծերում

  • Կառուցում եմ Laravel API-ներ (Laravel 8-ից 13) Passport-ով՝ token authentication-ի համար, մեկ բեքենդից սպասարկելով վեբ, մոբայլ և admin client-ներ։
  • Ռեստորանային պատվերների պլատֆորմում իրականացրել եմ Google և Apple sign-in վեբ և native մոբայլ հավելվածների համար, իսկ ներդրումային պորտալում՝ Google, LinkedIn և Facebook login Socialite-ի միջոցով։
  • Multi-tenant POS SaaS-ում authentication-ը օգտագործում է RS256-ով ստորագրված JWT-ներ, որոնք նորից ստուգվում են յուրաքանչյուր հարցման ժամանակ denylist-ով, 2FA անձնակազմի և օպերատորների համար, և device token-ներ դրամարկղերի համար։
  • Նույն POS SaaS-ը գործընկերների համար թողարկում է scope-ներով API key-եր՝ live/test բաժանմամբ, rate limit-ներով և rotation-ով, գումարած ժամանակով սահմանափակված impersonation, որը պահանջում է պատճառ։

Հարցեր և պատասխաններ

Q1Ո՞րն է տարբերությունը OAuth 2.0-ի և OpenID Connect-ի միջև։

OAuth 2.0-ը authorization framework է․ այն թույլ է տալիս client-ին ստանալ access token՝ օգտատիրոջ անունից API կանչելու համար՝ հաստատված scope-ների սահմաններում։ Այն ստանդարտ ոչինչ չի ասում այն մասին, թե ով է օգտատերը։ OpenID Connect-ը ինքնության շերտ է դրա վրա․ «openid» scope-ը խնդրելը ստիպում է authorization server-ին վերադարձնել նաև ID token՝ ստորագրված JWT՝ օգտատիրոջ identifier-ով, issuer-ով, audience-ով և expiry-ով, գումարած userinfo endpoint և discovery metadata։ Այսպիսով՝ OAuth-ը պատասխանում է «ի՞նչ կարող է անել այս հավելվածը» հարցին, OIDC-ն՝ «ո՞վ հենց նոր մուտք գործեց» հարցին։ «Sign in with Google»-ը OIDC է։

Q2Ի՞նչ է PKCE-ն և ինչու է այն հիմա պարտադիր։

PKCE-ն՝ Proof Key for Code Exchange, պաշտպանում է authorization code flow-ը code-ի ընդհատումից։ Client-ը գեներացնում է պատահական գաղտնիք (code_verifier), authorization հարցման հետ ուղարկում է միայն դրա SHA-256 hash-ը (code_challenge), իսկ հետագայում code-ը token-ների հետ փոխանակելիս պետք է ներկայացնի սկզբնական verifier-ը։ Հարձակվողը, որը գողանում է code-ը՝ նույն redirect scheme-ի համար գրանցված չարամիտ հավելվածի, log-երի կամ referrer-ի արտահոսքի միջոցով, չի կարող այն օգտագործել։ Այն նախագծվել էր մոբայլ և SPA client-ների համար՝ առանց secret-ների, բայց ընթացիկ best practice-ը (RFC 9700 և OAuth 2.1 draft-ը) այն խորհուրդ է տալիս բոլոր client-ների համար, ներառյալ server-side վեբ հավելվածները։

Q3Որտե՞ղ պետք է single-page հավելվածը պահի token-ները։

Ամենաանվտանգ սխեման դրանք ընդհանրապես բրաուզերում չպահելն է․ backend-for-frontend-ը (BFF) OAuth flow-ն աշխատեցնում է server-side, պահում token-ները և բրաուզերին տալիս HttpOnly, Secure, SameSite session cookie։ JavaScript-ը չի կարող այն կարդալ, ուստի XSS բագը չի կարող գողանալ երկարաժամկետ token-ները։ Եթե SPA-ն պետք է պահի token-ներ, access token-ը պահեք միայն հիշողության մեջ, դարձրեք կարճաժամկետ և օգտագործեք refresh token rotation՝ խիստ կյանքի տևողություններով։ Խուսափեք localStorage-ից որևէ երկարաժամկետ բանի համար, որովհետև ցանկացած ներարկված script կարող է այն կարդալ։

Q4JWT access token-ներ, թե՞ opaque token-ներ։

JWT-ները ինքնաբավ են և ստորագրված, ուստի API-ները կարող են դրանք ստուգել լոկալ՝ առանց ցանցային կանչի՝ արագ և լավ բաշխված ծառայությունների համար։ Թերությունը revocation-ն է․ JWT-ն մնում է վավեր մինչև ժամկետի ավարտը, եթե չեք ավելացնում denylist կամ session-ի տարբերակի ստուգում։ Opaque token-ները պատահական տողեր են, որոնք API-ն ստուգում է introspection-ով կամ բազայում որոնմամբ, ուստի revocation-ը ակնթարթային է՝ յուրաքանչյուր հարցման համար որոնման գնով (որը կարելի է քեշավորել)։ Տարածված փոխզիջում՝ 5–15 րոպեանոց կարճաժամկետ JWT access token-ներ, գումարած revoke արվող refresh token-ներ, գումարած denylist շտապ դեպքերի համար, օրինակ՝ կոտրված հաշվի։

Q5Ինչպե՞ս եք նախագծում scope-ները։

Scope-ները նկարագրում են, թե ինչ է թույլատրված token-ին անել, ուստի դրանք անվանեք բիզնես հնարավորությունների անուններով՝ orders:read, orders:create, profile:write, ոչ թե բազայի աղյուսակների կամ յուրաքանչյուր endpoint-ի անուններով։ Հավաքածուն պահեք փոքր և հասկանալի consent էկրանին։ Խնդրեք միայն այն scope-ները, որոնք client-ին պետք են, և ստուգեք դրանք յուրաքանչյուր route-ում։ Հիշեք, որ scope-ները կոպիտ են․ orders:read ունեցող token-ը դեռ պետք է անցնի object-level ստուգումներ, որպեսզի A օգտատերը չկարողանա կարդալ B օգտատիրոջ պատվերը։ First-party հավելվածների համար scope-ները նաև օգնում են սահմանափակել վնասը, օրինակ՝ kiosk-ի կամ դրամարկղի token-ին տալով շատ ավելի քիչ իրավունքներ, քան admin token-ին։

Q6Ինչպե՞ս ճիշտ իրականացնել logout-ը OAuth-ով։

Logout-ն ունի մի քանի շերտ։ Լոկալ՝ ավարտեք հավելվածի session-ը և ջնջեք պահված token-ները։ Authorization server-ում revoke արեք refresh token-ը (RFC 7009 revocation endpoint), որպեսզի այն չկարողանա նոր access token-ներ ստեղծել։ Գոյություն ունեցող JWT access token-ները մնում են վավեր մինչև ժամկետի ավարտը, ուստի պահեք դրանք կարճաժամկետ կամ ավելացրեք denylist-ին, եթե անմիջական կտրումը կարևոր է։ OpenID Connect-ով SSO-ի համար օգտագործեք RP-initiated logout՝ identity provider-ի session-ն էլ ավարտելու համար, և մտածեք back-channel logout-ի մասին, որպեսզի մյուս հավելվածները տեղեկացվեն։ Գաղտնաբառի փոփոխության կամ կոտրման կասկածի դեպքում revoke արեք օգտատիրոջ բոլոր token-ները։

Սենիոր մակարդակի հարցեր

S1Կկառուցեի՞ք ձեր սեփական authorization server-ը, թե՞ կօգտագործեիք managed identity provider։

Պրոդուկտների մեծ մասի համար ես OAuth server-ը զրոյից չէի գրի․ կընտրեի framework-ի հետ ինտեգրված server-ի, օրինակ՝ Laravel Passport-ի, self-hosted պրոդուկտի, օրինակ՝ Keycloak-ի, կամ managed provider-ի, օրինակ՝ Auth0-ի, Okta-ի, Entra ID-ի կամ Cognito-ի միջև։ Framework server-ները էժան են և օգտատերերին պահում են իմ սեփական բազայում՝ հիանալի են first-party վեբ և մոբայլ client-ների և գործընկերների պարզ հասանելիության համար։ Managed provider-ները հաղթում են, երբ պրոդուկտին պետք են enterprise SSO յուրաքանչյուր հաճախորդի համար, MFA քաղաքականություններ, SCIM, compliance հավաստագրեր և անոմալիաների հայտնաբերում․ վճարում եք ըստ օգտատիրոջ և ընդունում vendor lock-in-ը և նրանց տվյալների մոդելը։ Self-hosted Keycloak-ը մեջտեղում է՝ լիարժեք հնարավորություններ առանց ըստ օգտատիրոջ վճարների, բայց թարմացումները, scaling-ը և անվտանգության patch-երը ձեր պատասխանատվությունն են։ Որոշիչ գործոններն են հաճախորդների պահանջները (B2B SSO-ն մեծ գործոն է), թիմի հնարավորությունները և թե որքան կենտրոնական է ինքնությունը պրոդուկտի համար։

S2Ինչպե՞ս եք մշակում authorization-ը բազմաթիվ microservice-ների միջև։

Authentication-ը առանձնացնում եմ authorization-ի որոշումներից։ Edge gateway-ը կամ յուրաքանչյուր ծառայություն access token-ը ստուգում է լոկալ՝ ստորագրություն, issuer, audience, expiry՝ օգտագործելով քեշավորված JWKS։ Token-ները կրում են ինքնություն, tenant և կոպիտ scope-ներ, ոչ թե յուրաքանչյուր իրավունք, որովհետև իրավունքների մեծ հավաքածուները ուռեցնում են token-ները և հնանում։ Մանրակրկիտ որոշումները կայացվում են այն ծառայությունում, որին պատկանում են տվյալները, կամ policy engine-ում (OPA, Cedar կամ relationship-based համակարգ), որը սնուցվում է ընթացիկ տվյալներով։ Service-to-service կանչերի համար ծառայություններն օգտագործում են իրենց սեփական client credentials-ը կամ token exchange՝ ճիշտ audience-ով token ստանալու համար, այլ ոչ թե օգտատիրոջ token-ը ամենուր փոխանցում։ Փոխզիջումներ՝ ինքնաբավ JWT-ները արագ են, բայց դանդաղ են revoke արվում, ուստի կյանքի տևողությունները մնում են կարճ, կենտրոնական policy engine-ները ավելացնում են ցանցային hop, բայց կանոնները պահում են հետևողական և աուդիտելի։

S3Ի՞նչ է փոխվում OAuth 2.1-ի և ընթացիկ best practice-ի հետ՝ դասական OAuth 2.0-ի համեմատ։

Ուղղությունը դժվարությամբ ձեռք բերված դասերի համախմբումն է․ OAuth 2.1-ը դեռ draft է, բայց RFC 9700-ն արդեն կոդավորում է դրա մեծ մասը։ PKCE-ն դառնում է պարտադիր authorization code flow-ի համար բոլոր client-ների դեպքում։ Implicit grant-ը և resource owner password grant-ը հանվում են։ Redirect URI-ները պետք է ճշգրիտ համընկնեն։ Bearer token-ները չպետք է ուղարկվեն URL query string-երում։ Public client-ների refresh token-ները պետք է լինեն sender-constrained կամ rotate արվեն։ Հիմքից դուրս best practice-ը ավելացնում է sender-constrained token-ներ (DPoP կամ mTLS) բարձր արժեք ունեցող API-ների համար, PAR՝ authorization պարամետրերը պաշտպանելու համար, access token-ների կարճ կյանք և issuer identification՝ mix-up հարձակումները կանխելու համար։ Գործնականում միգրացիան սովորաբար նշանակում է ամենուր միացնել PKCE-ն, մոբայլ հավելվածներում հեռացնել password-grant մուտքերը՝ հօգուտ բրաուզերի վրա հիմնված code flow-ի, և խստացնել կյանքի տևողություններն ու rotation-ը։

Բառարան

Authorization server
Ծառայություն, որը authenticate է անում օգտատերերին և թողարկում access, refresh և ID token-ներ։
Access token
Կարճաժամկետ credential, որը client-ն ուղարկում է API-ին՝ ապացուցելու, որ թույլատրված է գործել։
Refresh token
Երկարաժամկետ credential, որն օգտագործվում է միայն նոր access token-ներ ստանալու համար՝ առանց նոր մուտքի։
ID token
OpenID Connect JWT, որը client-ին ասում է, թե ով է օգտատերը և ինչպես է մուտք գործել։
Scope
Անվանված իրավունք, որը խնդրում է client-ը և տրամադրում է օգտատերը, օրինակ՝ orders:read։
PKCE
Յուրաքանչյուր մուտքի գաղտնիք և դրա hash-ը, որոնք կանխում են գողացված authorization code-երի օգտագործումը։
JWKS
Public key-երի հրապարակված JSON հավաքածու, որն օգտագործվում է token-ների ստորագրությունները ստուգելու համար։
Client credentials grant
OAuth flow, որտեղ ծառայությունը authenticate է անում ինքն իրեն՝ առանց օգտատիրոջ մասնակցության։
DPoP
Մեխանիզմ, որը token-ները կապում է client-ի բանալու հետ, որպեսզի գողացված token-ը չկարողանա replay արվել։

Պրոդուկտի գաղափար ունե՞ք։Եկեք ստեղծենք այն։

Պատմեք ձեր գաղափարի, պրոդուկտի կամ թիմի մասին։ Սովորաբար պատասխանում եմ մեկ աշխատանքային օրվա ընթացքում։