OAuth 2.0 su Keycloak identity server

Kas tas OAuth 2.0 ir kodėl jis svarbus

Prisiminkite situaciją: norite prisijungti prie naujos aplikacijos ir matote mygtuką „Prisijungti su Google” arba „Prisijungti su Facebook”. Paspaudžiate, sutinkate su prieiga prie tam tikros informacijos, ir po kelių sekundžių jau esate viduje. Nereikėjo kurti naujo slaptažodžio, nereikėjo užpildyti ilgų registracijos formų. Tai veikia dėl OAuth 2.0 – autorizacijos protokolo, kuris tapo de facto standartu šiuolaikinėse aplikacijose.

OAuth 2.0 nėra autentifikacijos protokolas, nors daugelis žmonių taip mano. Tai autorizacijos protokolas, kuris leidžia aplikacijoms gauti ribotą prieigą prie vartotojo resursų kitoje sistemoje, neatskleisdamas slaptažodžio. Skirtumas gal atrodo subtilus, bet jis fundamentalus. Autentifikacija atsako į klausimą „kas tu esi?”, o autorizacija – „ką tau leidžiama daryti?”.

Protokolo populiarumas augo eksponentiškai, nes jis išsprendė realią problemą: kaip leisti trečiosioms aplikacijoms pasiekti vartotojo duomenis be to, kad reikėtų dalintis slaptažodžiais. Prieš OAuth erą, jei norėjote, kad kažkokia aplikacija pasiektų jūsų Gmail pašto dėžutę, turėjote jai atiduoti savo Google slaptažodį. Tai buvo saugumo košmaras.

Keycloak – ne tik dar vienas identity serveris

Kai kalbame apie OAuth 2.0 implementaciją, Keycloak išsiskiria kaip vienas galingiausių open-source sprendimų. Red Hat sukurtas ir palaikomas projektas siūlo ne tik OAuth 2.0 palaikymą, bet ir pilną identity ir access management (IAM) sprendimą. Tai reiškia, kad gaunate Single Sign-On (SSO), vartotojų federaciją, socialinių tinklų integraciją, dviejų faktorių autentifikaciją ir daug daugiau iš dėžės.

Kas Keycloak daro ypač patrauklų – tai jo administravimo konsolė. Vietoj to, kad rašytumėte konfigūracijos failus ar SQL užklausas, turite vizualią sąsają, kur galite sukurti realms (domenus), klientus, vaidmenis ir vartotojus. Tai žymiai sumažina įėjimo barjerą ir leidžia greitai prototipuoti sprendimus.

Dar vienas privalumas – Keycloak palaiko ne tik OAuth 2.0, bet ir OpenID Connect (OIDC), SAML 2.0 ir kitus protokolus. Tai reiškia, kad jūsų sistema gali bendrauti su įvairiausiais klientais ir sistemomis, naudojančiomis skirtingus standartus.

OAuth 2.0 srautai ir kada juos naudoti

OAuth 2.0 apibrėžia kelis autorizacijos srautus (flows), ir kiekvienas iš jų skirtas skirtingiems scenarijams. Supratimas, kurį srautą naudoti, yra kritiškai svarbus saugiam implementavimui.

Authorization Code Flow yra saugiausias ir rekomenduojamas metodas web aplikacijoms. Čia vartotojas nukreipiamas į Keycloak prisijungimo puslapį, po sėkmingo prisijungimo gaunamas autorizacijos kodas, kurį aplikacija iškeičia į access token. Svarbu, kad šis keitimas vyksta backend’e, todėl token niekada neatsiduria naršyklėje. Jei kuriate bet kokią serverio pusės aplikaciją, tai turėtų būti jūsų pirmas pasirinkimas.

Implicit Flow buvo populiarus single-page aplikacijoms (SPA), bet šiandien jis laikomas pasenusiu ir nesaugiu. Problema ta, kad access token grąžinamas tiesiogiai URL fragmente, o tai kelia saugumo riziką. Vietoj jo dabar rekomenduojama naudoti Authorization Code Flow su PKCE.

PKCE (Proof Key for Code Exchange) – tai Authorization Code Flow praplėtimas, sukurtas mobiliosioms aplikacijoms ir SPA. Jis prideda papildomą saugumo sluoksnį, generuodamas atsitiktinį code verifier ir code challenge. Net jei piktavalis perims autorizacijos kodą, jis negalės jo iškeisti į token be code verifier.

Client Credentials Flow naudojamas machine-to-machine komunikacijai, kai nėra vartotojo. Pavyzdžiui, jūsų backend servisas nori pasiekti kitą API. Čia tiesiog pateikiami kliento credentials ir gaunamas access token.

Resource Owner Password Credentials Flow – čia aplikacija tiesiogiai priima vartotojo slaptažodį. Tai prieštarauja OAuth filosofijai ir turėtų būti vengiama, išskyrus labai specifines situacijas, kai kiti srautai neįmanomi.

Keycloak konfigūravimas praktikoje

Pradėkime nuo Keycloak diegimo. Paprasčiausias būdas – Docker:

docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:latest start-dev

Po kelių minučių turėsite veikiančią Keycloak instanciją adresu http://localhost:8080. Prisijunkite su admin/admin ir pirmiausia pakeiskite slaptažodį – tai development režimas, bet gerų įpročių niekada per daug.

Pirmasis žingsnis – sukurti realm. Realm yra izoliuotas domenas, turintis savo vartotojus, klientus, vaidmenis ir konfigūraciją. Galite turėti atskirą realm kiekvienai aplinkai (dev, staging, production) arba kiekvienam projektui. Administravimo konsolėje paspauskite „Create realm” ir pavadinkite jį, pavyzdžiui, „myapp”.

Dabar reikia sukurti klientą – tai jūsų aplikacija, kuri naudos Keycloak autentifikacijai. Eikite į Clients → Create client. Svarbiausios nuostatos:

  • Client ID – unikalus identifikatorius, pavyzdžiui, „myapp-frontend”
  • Client Protocol – pasirinkite openid-connect
  • Access Type – public SPA aplikacijoms, confidential backend aplikacijoms
  • Valid Redirect URIs – kur Keycloak gali nukreipti po autentifikacijos, pvz., http://localhost:3000/*
  • Web Origins – CORS nustatymai, dažniausiai tas pats kaip redirect URI

Jei pasirinkote confidential kliento tipą, gausite Client Secret – saugokite jį kaip savo akių vyzdį. Šis secret niekada neturėtų patekti į frontend kodą ar viešus repository.

Integruojame su React aplikacija

Praktinis pavyzdys visada padeda geriau suprasti. Tarkime, kuriate React aplikaciją ir norite integruoti Keycloak autentifikaciją. Geriausia biblioteka tam – keycloak-js.

Pirmiausia įdiekite:

npm install keycloak-js

Sukurkite Keycloak konfigūraciją:


const keycloakConfig = {
url: 'http://localhost:8080/',
realm: 'myapp',
clientId: 'myapp-frontend'
};

Inicializuokite Keycloak aplikacijos pradžioje:


import Keycloak from 'keycloak-js';

const keycloak = new Keycloak(keycloakConfig);

keycloak.init({
onLoad: 'login-required',
checkLoginIframe: false
}).then(authenticated => {
if (authenticated) {
console.log('Vartotojas prisijungęs');
console.log('Access token:', keycloak.token);
}
});

Parametras onLoad: 'login-required' reiškia, kad vartotojas bus iš karto nukreiptas į prisijungimo puslapį, jei nėra autentifikuotas. Alternatyva – 'check-sso', kuri tiesiog patikrina, ar vartotojas prisijungęs, bet nenukreipia.

Svarbu suprasti token galiojimo laiką. Access token paprastai galioja 5-15 minučių, o refresh token – daug ilgiau. Keycloak-js biblioteka automatiškai atnaujina token, bet galite tai kontroliuoti:


keycloak.updateToken(30).then(refreshed => {
if (refreshed) {
console.log('Token atnaujintas');
}
}).catch(() => {
console.log('Nepavyko atnaujinti token');
keycloak.login();
});

Čia sakome: jei token baigs galioti per 30 sekundžių, atnaujink jį. Tai turėtumėte daryti prieš kiekvieną API užklausą.

Backend apsauga su Spring Boot

Frontend autentifikacija – tik pusė istorijos. Jūsų backend API turi patikrinti, ar gaunami token yra validūs. Spring Boot su Spring Security tai daro labai elegantiškai.

Pridėkite dependencies:


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

Konfigūruokite application.yml:


spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://localhost:8080/realms/myapp

Spring automatiškai parsisiųs Keycloak public key ir validuos JWT token. Dabar galite apsaugoti endpoint’us:


@Configuration
@EnableWebSecurity
public class SecurityConfig {

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt());
return http.build();
}
}

Keycloak token’e gali būti įvairių claim’ų, įskaitant vaidmenis (roles). Tačiau Keycloak saugo juos šiek tiek kitaip nei Spring tikisi. Reikia sukurti konverterį:


@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
grantedAuthoritiesConverter.setAuthoritiesClaimName("realm_access.roles");
grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");

JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
return jwtAuthenticationConverter;
}

Pažangesnės funkcijos ir best practices

Kai bazinė integracija veikia, laikas pagalvoti apie pažangesnius scenarijus ir saugumo aspektus.

Token saugojimas – viena dažniausių klaidų yra saugoti access token localStorage. Tai daro jį pažeidžiamą XSS atakoms. Geresnė alternatyva – httpOnly cookies arba memory storage. Keycloak-js pagal nutylėjimą saugo token’us memory, kas yra saugiau, bet reiškia, kad vartotojas praras sesiją atnaujinus puslapį. Čia reikia balanso tarp saugumo ir UX.

Refresh token rotation – Keycloak palaiko refresh token rotation, kai kiekvieną kartą naudojant refresh token, gaunamas naujas. Tai sumažina riziką, jei refresh token būtų pavogtas. Įjunkite tai realm nustatymuose: Realm Settings → Tokens → Revoke Refresh Token.

Fine-grained authorization – OAuth 2.0 suteikia prieigą prie resursų, bet neapibrėžia, kaip tiksliai kontroliuoti tą prieigą. Keycloak siūlo Authorization Services – galingą mechanizmą, leidžiantį apibrėžti politikas, leidimus ir resursus. Pavyzdžiui, galite sukurti politiką „vartotojas gali redaguoti tik savo dokumentus” ir ją įgyvendinti deklaratyviai, be kodo.

User Federation – jei jau turite egzistuojančią vartotojų bazę LDAP ar Active Directory, Keycloak gali su ja integruotis. Eikite į User Federation → Add provider ir pasirinkite LDAP. Vartotojai galės prisijungti su savo esamais credentials, o Keycloak sinchronizuos duomenis.

Social Login – pridėti „Prisijungti su Google” ar „Prisijungti su GitHub” yra trivialiai paprasta. Identity Providers → Add provider → pasirinkite norimą tiekėją. Reikės sukurti OAuth aplikaciją atitinkamoje platformoje ir įvesti Client ID bei Secret į Keycloak. Po to vartotojai matys papildomus prisijungimo mygtukus.

Multi-tenancy – jei kuriate SaaS aplikaciją, kur kiekvienas klientas turi atskirą „tenant”, galite naudoti atskirus realms arba groups/roles tame pačiame realm. Atskiri realms suteikia geresnę izoliaciją, bet sudėtingesni valdyti. Groups/roles paprastesni, bet visi vartotojai tame pačiame realm.

Debugging ir dažniausios problemos

OAuth 2.0 ir Keycloak integracija ne visada vyksta sklandžiai. Štai keletas dažniausių problemų ir kaip jas spręsti.

CORS klaidos – jei matote „Access to fetch at… has been blocked by CORS policy”, patikrinkite Keycloak kliento Web Origins nustatymą. Jis turi atitikti jūsų aplikacijos origin. Development metu galite naudoti „*”, bet production aplinkoje visada nurodykite konkretų domain.

Invalid redirect_uri – Keycloak griežtai tikrina redirect URI. Jis turi tiksliai atitikti vieną iš Valid Redirect URIs sąraše. Net trailing slash gali sukelti problemą. Jei naudojate wildcards, įsitikinkite, kad jie teisingai sukonfigūruoti.

Token validation fails – jei backend atmeta token, patikrinkite issuer URI. Jis turi tiksliai atitikti Keycloak realm URL, įskaitant protokolą (http/https) ir portą. Taip pat įsitikinkite, kad laikrodžiai sinchronizuoti – JWT token turi iat (issued at) ir exp (expiration) laikus.

Roles neatvaizduojami – jei vaidmenys nepersiduoda į aplikaciją, patikrinkite Client Scopes. Įsitikinkite, kad „roles” scope yra įtrauktas į jūsų klientą. Taip pat galite peržiūrėti token turinį adresu jwt.io – ten pamatysite, kokie claim’ai realiai yra token’e.

Session timeout problemos – jei vartotojai skundžiasi, kad nuolat turi prisijunginėti, peržiūrėkite Realm Settings → Tokens nustatymus. SSO Session Idle ir SSO Session Max kontroliuoja, kiek laiko sesija galioja. Taip pat įsitikinkite, kad frontend’as teisingai atnaujina token’us.

Debugging’ui naudokite Keycloak Events. Realm Settings → Events → įjunkite Save Events ir Login Events. Čia matysite visus autentifikacijos bandymus, klaidas ir sėkmingus prisijungimus. Tai neįkainojama informacija sprendžiant problemas.

Kai viskas sueina į vieną vietą

OAuth 2.0 su Keycloak – tai galingas derinys, leidžiantis sukurti saugią, mastelio ir šiuolaikišką autentifikacijos sistemą. Taip, pradžioje gali atrodyti sudėtinga – tiek daug koncepcijų, srautų, konfigūracijų. Bet kai suprantate pagrindines idėjas ir matote, kaip viskas veikia kartu, tai tampa intuityviu.

Svarbiausias dalykas – nesistenkite viską padaryti iš karto. Pradėkite nuo paprasto Authorization Code Flow, įsitikinkite, kad jis veikia, ir tik tada pridėkite papildomas funkcijas. Testuokite saugumo aspektus – bandykite pakeisti token’us, naudoti pasenusį token’ą, prieiti be autorizacijos. Geriau rasti problemas development’e nei production’e.

Keycloak dokumentacija yra išsami, bet kartais gali būti per daug techninė. Nebijokite eksperimentuoti administravimo konsolėje – dauguma nustatymų turi tooltip’us, paaiškinančius, ką jie daro. Sukurkite test realm, kur galite laisvai bandyti įvairias konfigūracijas.

Ir paskutinis patarimas – sekite saugumo naujienas. OAuth 2.0 ir OpenID Connect standartai evoliucionuoja, atsiranda naujos best practices, senosios pripažįstamos nesaugiomis. Pavyzdžiui, Implicit Flow dar prieš kelerius metus buvo rekomenduojamas SPA, o dabar yra deprecated. Technologijų pasaulis nestovi vietoje, ir saugumo srityje tai ypač svarbu.

Daugiau

Saugūs mokėjimai internete, ką tikrinti prieš patvirtinant