Predstavme si webovú aplikáciu s REST API, ktorá spravuje používateľkine chránené údaje — napríklad databázu domácich kvetín.
Takáto aplikácia:
-
beží napr. na https://domacekvetiny.io/api
-
prístup k údajom vyžaduje autorizáciu, čiže schválený prístup
| Takáto aplikácia nazýva Resource Server. Chránené údaje sú zdroje, teda protected resources. |
A predstavme si druhú aplikáciu, ktorá chce automatizovane zalievať domáce kvetiny používateľky.
Na to potrebuje prístup ku používateľkiným chráneným údajom, teda zoznamu jej kvetín.
| OAuth 2.0 je protokol, ktorý umožní používateľke delegovať prístup k svojim chráneným zdrojom na vybranú aplikáciu. Táto aplikácia sa volá klient a pristupuje k chráneným zdrojom v mene používateľky (on behalf of). |
Používateľka tak vie delegovať prístup k svojim domácim kvetinám na automatizovaný zalievač.
| Klientom môže byť webová aplikácia, mobilná aplikácia, či napríklad frontendová aplikácia typu SPA. |
Autorizačný server ako centrálny bod
Delegovanie prístupu spravuje autorizačný server, ktorý zodpovedá hotelovej recepcii.
- Registrovaní klienti
-
autorizačný server pozná registrovaných klientov
- Používatelia a ich prihlasovacie údaje
-
autorizačný server slúži ako databáza používateľov a hesiel
- Prístupové tokeny
-
autorizačný server vydáva autorizovaným klientom tokeny, niečo ako šatňové žetóny či metaforické karty, ktoré umožňujú prístup k chráneným zdrojom.
Autorizačné tance
OAuth 2.0 podporuje štyroch participantov, ktorí vzájomne „tancujú“ pri delegovaní prístupu.
Ak chce klient-zalievač pristúpiť k zoznamu kvetov:
-
Požiada používateľa o autorizáciu.
-
Používateľ poskytne autorizačný kód.
-
Klient vezme autorizačný kód a požiada autorizačný server o výmenu za prístupový token.
-
Autorizačný server vydá prístupový token.
-
Klient priloží prístupový token k volaniam databázového servera.
Inými slovami:
Zalievač: Hej, Miriamin skleník! Potrebujem zaliať kvety!
Miriamin skleník: A Miriam o tom vie?
Zalievač: Nie, idem sa jej spýtať.
Zalievač: Hej, Miriam, potrebujem ti zaliať tvoje kvety!
Si s tým OK?
Miriam: Jasné, tu máš autorizačný kód.
Zalievač: Hej, autorizačný server, potrebujem Miriam zaliať kvety!
Povolila mi to, tu mi dala autorizačný kód!
Autorizačný server: Kód vyzerá dobre. Tu je plechový žetón, choď s ním do
jej skleníka.
Zalievač: Hej, Miriamin skleník! Potrebujem zaliať kvety!
Tu je token od autorizačného servera,
že to môžem spraviť!
| Toto je najvšeobecnejší „tanec“. Vzájomná komunikácia medzi rolami a postupnosť krokov závisí hlavne od typu klienta (mobil? SPA?) Konkrétny tanec sa nazýva grant (terminológia OAuth 2.0) alebo flow (terminológia OpenID Connect 1.0). |
OAuth 2.0
OAuth 2.0 je oficiálne:
OAuth 2.0 Authorization Framework (RFC 6749) umožní získať aplikáciam tretích strán získať prístup k službe nad HTTP v mene používateľky po získaní jej súhlasu.
OAuth 2.0 je o autorizácii!
| V OAuth 2.0 sa nič nehovorí o autentifikácii — prihlásení. Tento protokol je len o delegovaní prístupu! |
OAuth 2.0 je „len OAuth“.
| Existuje zastaralá špecifikácia OAuth 1.0, ktorá je odlišná a nepoužívaní. Odteraz už „OAuth“ znamená vždy „OAuth 2.0“. |
Tokeny sú netransparentné
OAuth nehovorí nič o podobe či formáte prístupového tokenu.
OpenID Connect 1.0 (OIDC)
OIDC je nadstavba nad OAuth, ktorá:
-
umožní autentifikovať používateľku.
-
dokáže vydať preukaz identity používateľky, v mene ktorej sa získavajú chránené zdroje.
-
do odpovede HTTP po zavolaní endpointu pre získanie tokenu pridá ešte jeden token — identity token ako dôkaz prihlásenej používateľky.
-
umožní získať základné informácie o používateľskom profile z autorizačného servera cez REST API
-
určuje, že autorizačný token (access token) sa pri volaniach prikladá do hlavičky
Authorization.
| OpenID Connect je o autentifikácii používateľky. Je dokonca ho možné použiť na jednotné prihlasovanie (Single Sign On) do viacerých klientov či serverov zdrojov. |
OIDC používa alternatívne pojmy:
- flow
-
ekvivalent grant v OAuth. Reprezentuje konkrétny „tanec“ medzi entitami a postupnosť krokov
- OpenID Provider či Identity Provider (IdP)
-
autorizačný server, ktorý dokáže autentifikovať používateľku a poskytnúť informácie o jej identite.
| Mnoho článkov automaticky používa „flow“ namiesto „grantu“ aj pre tance z OAuth. |
Typické situácie
„Prihlás ma cez Google“
Naša backendová aplikácia môže podporovať prihlásenie cez autorizačný server tretej strany.
Používateľka sa tak napríklad prihlási svojim kontom na GMaili a naša backendová aplikácia nemusí vôbec spravovať heslá.
Naša aplikácia je klientom zaregistrovaným v autorizačnom serveri.
Veľkí internetoví hráči poskytujú vlastné autorizačné servery:
-
Google poskytuje certifikovaný OIDC server.
-
Facebook dáva k dispozícii OIDC Facebook Login
-
GitHub poskytuje protokol OAuth
| Toto je spôsob dosiahnutia Single Sign On, teda jednotného prihlasovania. Klient si nemusí pamätať žiadne loginy ani heslá. |
Chcem mať databázu používateľov, ale nechcem ju programovať
Môžeme si vybrať existujúci autorizačný server:
-
Keycloak, open source, Java, sponzoruje RedHat
-
Okta, cloud, bezplatný do 100 mesačných aktívnych používateliek
-
Shibboleth IdP s OIDC pluginom, open source, Java
Potrebujem klienta či resource server?
Client
Client je typicky webová aplikácia bežiaca na serveri, alebo mobilná appka, prípadne webový frontend, ktorý beží v prehliadači ako aplikácia SPA. Klient konzumuje chránené zdroje, obvykle v mene používateľky.
| Klient musí byť evidovaný v autorizačnom serveri. |
Resource Server
Resource Server je typicky REST API, ktoré produkuje chránené zdroje.
Prístup k nemu vyžaduje prístupový token. Ak využívame OIDC a token je vo formáte JWT, takýto server dokáže:
-
získať verejné kľúče z autorizačného servera a overiť digitálny podpis tokenu
-
vyčítať z tokenu jednotlivé tvrdenia (claims) a získať informácie o rolách či dodatočných prístupových oprávneniach.
| Resource Server nepotrebuje byť evidovaný v autorizačnom serveri. |
Klienti
Ak potrebujeme aplikáciu, ktorá konzumuje chránené zdroje, musíme:
-
Programovať klienta (client).
-
Zaevidovať ho v autorizačnom serveri.
-
Získať jeho jednoznačný identifikátor: Client ID.
-
Tento identifikátor použiť v konfigurácii klienta.
Typ klienta?
OAuth rozoznáva dva druhy klientov:
- confidential
-
klienti s uzavretým kódom, ktoré bežia na serveri. Dokáže bezpečne udržiavať citlivý údaj „client secret“, ktorým sa sám identifikuje a autorizuje voči autorizačnému serveru.
Dôverný klient dokáže posielať na autorizačný server dvojicu Client ID + Client Secret, ktorá vystupuje v role loginu a hesla samotného klienta. Autorizačný server tak dokáže overiť identitu samotného klienta.
- public
-
klienti s otvoreným kódom, ktorí nedokážu bezpečne preukázať svoju identitu, ani spravovať svoje klientske tajomstvo.
Príklady:
-
backendová aplikácia v Java/Spring Boot uzavretá na serveri je confidential — klientske tajomstvo client secret nie je možné zistiť ani odhaliť pri dodržaní bezpečnostných zásad.
-
frontend v Reacte je public — nie je technicky možné ochrániť klientske tajomstvo, ktoré je možné triviálne získať z webového prehliadača
-
mobilná aplikácia je public — jej dekompiláciou je totiž možné získať client secret a zneužiť ho.
-
servisná aplikácia v Go uzavretá na serveri je confidential.
Aký flow?
Oauth historicky špecifikoval viacero grantov (flowov).
Ktorý z nich zvoliť?
Zistime, čo je náš klient zač a potom:
- Je to React/Angular aplikácia typu SPA v prehliadači?
-
Authorization Code with PKCE, verejný klient
- Je to mobilná appka?
-
Authorization Code with PKCE, verejný klient
- Je to mobilná appka, ktorej naozaj dôverujeme a dokážeme jej zveriť používateľkin login a heslo?
-
Resource Owner Password Credentials, verejný klient
- Je to webová backendová aplikácia?
-
Authorization Code with PKCE, dôverný klient
- Je to servisná aplikácia / démon / monitorovacia aplikácia na serverovom backende, kde nie je potrebné prihlásenie používateľky?
-
Client Credentials, dôverný klient
- Je to serverová backendová aplikácia, ktorej vieme zveriť používateľkin login a heslo?
-
Resource Owner Password Credentials, dôveryhodný klient
- Používame autorizačný server ako databázu používateľov, lebo migrujeme na OAuth?
-
Resource Owner Password Credentials; klient podľa typu aplikácie.
- Beží aplikácia na televízore, hernej konzole, či inom zariadení, kde nevieme rozumne zadávať text?
-
Device Authorization, verejný klient
Tri tokeny v OIDC
OIDC vracia v odpovedi z tokenového endpointu tri tokeny:
- identity token
-
token s údajmi o identite prihlásenej používateľky. Ide o token autentifikácie. Je vždy vo formáte JWT a musí byť podpísaný privátnym kľúčom servera.
- access token
-
prístupový token reprezentujúci autorizáciu. Ide o token autorizácie.
- refresh token
-
dlhotrvajúci token umožňujúci predĺžiť vydať nový prístupový token, ak predošlý vyprší.
|
OIDC prikazuje identifikačné tokeny vo formáte JWT. O formáte prístupových tokenoch nehovorí nič, ale konvencia mnohých autorizačných serverov aj tieto tokeny poskytuje vo formáte JWT. |
{
"id_token": "eyJh...", (1)
"access_token": "eyJh....", (2)
"expires_in": 60,
"scope": "openid profile email", (3)
"token_type": "Bearer",
"not-before-policy": 0,
"session_state": "074ffb5f-f0ea-4182-b93d-023e9669f010"
}
| 1 | Token s identitou v JWT formáte. |
| 2 | Prístupový token, tiež v JWT. |
| 3 | Scopes, ktoré umožnil autorizačný server. |
Identity Token — Identitný token
| Identity Token dokazuje, že autorizačný server prihlásil používateľku. |
{
"exp" : 1681033070,
"iat" : 1681033010,
"auth_time" : 1681033010,
"jti" : "eadb5025-870b-4fdc-b17d-4996d8820b6e",
"iss" : "http://localhost:8080/realms/master",
"aud" : "exabank",
"sub" : "212aa1c7-667e-4c2b-a99b-4c050ea94644",
"typ" : "ID",
"azp" : "exabank",
"nonce" : "9qYmGQT4z6llfQuDgt5FyOexIz2SKsDL-LScEOwtpvo",
"session_state" : "3b71e2a2-f8fb-43e3-aa8a-45ee0a6d7afd",
"at_hash" : "KJq8-LeZZ35yNmpAzg7xrw",
"acr" : "1",
"sid" : "3b71e2a2-f8fb-43e3-aa8a-45ee0a6d7afd",
"email_verified" : true,
"name" : "Jane Doe",
"preferred_username" : "janedoe",
"given_name" : "Jane",
"family_name" : "Doe",
"email" : "jane.doe@example.com"
}
Access Token — Prístupový token
|
Prístupový token je preukaz oprávnenia prístupu k chráneným dátam. |
Prístupový token má obmedzenú platnosť, obvykle pol minúty, minútu, či inú krátku dobu.
Hoci to OIDC štandard nevyžaduje, často je vo formáte JWT, podpísaný privátnym kľúčom servera.
{
"exp" : 1681033070,
"iat" : 1681033010,
"auth_time" : 1681033010,
"jti" : "46892562-a643-4186-bba9-dee3ab2bd735",
"iss" : "http://localhost:8080/realms/master",
"sub" : "212aa1c7-667e-4c2b-a99b-4c050ea94644",
"typ" : "Bearer",
"azp" : "exabank",
"nonce" : "9qYmGQT4z6llfQuDgt5FyOexIz2SKsDL-LScEOwtpvo",
"session_state" : "3b71e2a2-f8fb-43e3-aa8a-45ee0a6d7afd",
"acr" : "1",
"allowed-origins" : [ "http://localhost:9999" ],
"realm_access" : {
"roles" : [ "default-roles-master", "offline_access", "uma_authorization" ]
},
"resource_access" : {
"account" : {
"roles" : [ "manage-account", "manage-account-links", "view-profile" ]
}
},
"email_verified" : true, (1)
"name" : "Jane Doe",
"preferred_username" : "janedoe",
"given_name" : "Jane",
"family_name" : "Doe",
"email" : "jane.doe@example.com"
}
| 1 | Tento prístupový token obsahuje aj údaje o profile. Nie je to však pravidlo! Keycloak tu len opakuje údaje z identifikačného profilu. |
|
Identifikačný token a prístupový token slúžia na odlišné prípady! Najdôležitejšie je ich nepopliesť!
|
Refresh Token — Obnovovací token
Prístupové tokeny majú krátku platnosť, obvykle v desiatkach sekúnd.
| Refresh Token (Obnovovací token) slúži na získanie nového platného autorizačného tokenu. |
Autorizačný server môže pri vydávaní prístupového tokenu vydať aj refresh token s dlhou platnosťou.
Klient potom dokáže v autorizačnom serveri vymeniť neplatný prístupový token a obnovovací token za nový autorizačný token.
|
Niektoré autorizačné servery vracajú aj obnovovací token v tvare JWT. Obnovovací token (Refresh Token) z Keycloaku
|
Odovzdávanie prístupového tokenu medzi klientom a serverom zdrojov
OIDC určuje, že prístupový token (Access Token) sa vždy prikladá k volaniam API s chránenými údajmi do hlavičky HTTP Authorization vo formáte:
Authorization: Bearer <access_token>
Čo sú scopes
Klient môže pri autorizácii žiadať o rozličné scopes, čo je rozsah platnosti tokenu.
| Scopes je možné použiť na aplikačné oprávnenia, či uvedenie druhu údajov, ktoré klient túži získať. |
- Keycloak
-
dokáže poskytnúť scope pre používateľkin e-mail (
email), používateľkin profil (profile), či pridelené roly (roles). - GitHub
-
poskytuje scope pre jednotlivé privilégiá, napr. scope
repoautorizuje pre úplný prístup k používateľkinym repozitárom, či scopeuser:readumožní čítať údaje z používateľkinho profilu.
Na technickej úrovni je scopes ľubovoľná množina reťazcov, kde význam je na dohode medzi klientom a autorizačným serverom.
-
Autorizačný server má pri evidovanom klientovi povedané, aké scopy mu dokáže poskytnúť.
-
Klient dokáže pri autorizácii požiadať o konkrétnu množinu scopov a autorizačný server usúdi, ktoré z nich dokáže splniť.
Pri použití OIDC sa očakáva, že klient požiada pri autorizácii o scope openid.
Bez neho sa použije len štandardný protokol OAuth bez nadstavby OpenID Connect.
|
Na obrázku vidíme, ako klient (Spring Boot OAuth Client) požiadal autorizačný server o scope openid, ale získal autorizačný kód s rozšírenou množinou scopes:
-
openidkvôli protokolu OIDC -
profiles používateľkiným profilom -
emails možnosťou získať e-mail používateľky
Autorizačný server môže pridelené scopes uviesť aj do prístupového tokenu — ak ide o token vo formáte JWT, tak do niektorého z tvrdení claims.
Consent — výslovný súhlas s delegovaním
Autorizačný server môže v evidencii klienta určiť, že pri autorizácii je nutný explicitný súhlas používateľky so získavaním chránených zdrojov v jej mene.
Dialóg potom vyzerá zhruba nasledovne:
Zalievač: Hej, Miriamin skleník! Potrebujem zaliať kvety!
Miriamin skleník: A Miriam o tom vie?
Zalievač: Nie, idem sa jej spýtať.
Zalievač: Hej, Miriam, potrebujem ti zaliať tvoje kvety!
Si s tým OK?
Autorizačný server: Hej, Miriam, mám tu Zalievača, chceš ho autorizovať
a umožniť mu prístup?
Miriam: Áno, autorizačný server, som s tým OK.
Autorizačný server: Zalievač, nech sa páči tu máš autorizačný kód.
Pri prvom prístupe si tak autorizačný server vyžiada explicitný súhlas — consent.
V prípade Keycloaku sa jednotlivé položky zo súhlasu sa priamo mapujú na scopes, ktoré poskytuje autorizačný server:
- User profile
-
mapovaný na scope
profile. - Email address
-
mapovaný na scope
email. - User roles
-
mapovaný na scope
rolesobsahujúci používateľské roly konfigurovateľné v Keycloaku.
V prípade GitHubu v role autorizačného servera vyzerá súhlas nasledovne:
Vidíme, že klient spring-boot-repo-browser požaduje autorizáciu.
V GitHube je prístup k verejnému profilu súčasťou automatického scope, v prípade, že oň klient nežiada, ale i napriek tomu je ho vidno v sekcii Personal user data.
Metadáta autorizačného servera
Autorizačný server môže poskytovať viacero endpointov cez REST či HTTP. Minimalistická verzia očakáva:
-
autorizačný endpoint pre získanie autorizačného kódu
-
endpoint pre získanie tokenu
Ak používame OIDC, pribudne viacero endpointov, napr.:
-
získanie informácií o používateľke (userinfo)
-
získanie verejných kľúčov pre overenie digitálnych podpisov tokenov JWT
| Špecifikácia OpenID Connect Discovery určuje endpoint, ktorý poskytne jednotný formát pre uvedené endpointy. |
-
autorizačný server Google ponúka endpoint https://accounts.google.com/.well-known/openid-configuration s jednotlivými údajmi
-
autorizačný server Facebooku tiež ponúka endpoint https://www.facebook.com/.well-known/openid-configuration/
- Keycloak
-
k dispozícii je endpoint, napr. na adrese http://localhost:8080/realms/master/.well-known/openid-configuration
Endpoint podporovaný Googlom vyzerá napríklad nasledovne:
{
"authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth", (1)
"token_endpoint": "https://oauth2.googleapis.com/token", (2)
"jwks_uri": "https://www.googleapis.com/oauth2/v3/certs", (3)
"scopes_supported": [ "openid", "email", "profile" ], (5)
"grant_types_supported": [ (4)
"authorization_code",
"refresh_token",
"urn:ietf:params:oauth:grant-type:device_code",
"urn:ietf:params:oauth:grant-type:jwt-bearer"
]
}
| 1 | Endpoint pre získanie autorizačného kódu. |
| 2 | Endpoint pre získanie prístupového tokenu (JWT) |
| 3 | Endpoint, ktorý poskytne informácie o verejných kľúčoch, ktorými sa podpísali tokeny JWT. |
| 4 | Zoznam podporovaných flowov. |
| 5 | Scopes, ktoré tento autorizačný server podporuje. |
| Spring Boot a jeho integrácia s OAuth dokáže nastaviť aplikáciu podľa tohto metadátového endpointu. |
JWT
| JSON Web Token (JWT) je špecifikácia pre tokeny. |
Token JWT pozostáva z 3 častí:
-
hlavička: JOSE Header
-
telo tokenu: payload
-
digitálny podpis: signature
Všetky časti sú kódované pomocou Base64 a vzájomne oddelené bodkou.
Telo tokenu i hlavička sú vo formáte JSON, kde jednotlivé kľúče a ich hodnoty sa nazývajú claim (tvrdenia).
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2ODEwNTQxNzd9.SURFKdNgESGuubuvN9FgzBT929SjFmqXKJ29SSGM0vM
Druhý blok medzi dvoma bodkami je telo s jediným tvrdením:
{
"iat" : 1681054177 (1)
}
| 1 | Tvrdenie iat obsahuje dátum vydania tokenu. |
Prvý blok po bodku je hlavička a v nej claimy alg ako algoritmus pre podpis a typ tokenu.
{
"alg": "HS256",
"typ": "JWT"
}
Tretí blok obsahuje digitálny podpis hlavičky a tela správy.
| Algoritmus HMAC with SHA-256 využíva symetrickú šifru a spolieha sa na to, že autor i overovateľ tokenu poznajú spoločné heslo. |