pickstar
pickstar

Reputation: 43

How to get token via Keycloak + external SSO

I'm writing a backend implementation of authentication in an external sso. I use Spring Boot 3 for microservices, Keycloak is responsible for authentication. Keycloak contains multiple realms to support multi-tenancy. Our services and front use jwt tokens for authorization, so as a result of sso authentication we should receive a token of our Keycloak.

Expected implementation:

  1. frontend calls “bff” (backend for frontend) microservice, passing the user’s login as input.
  2. “bff” calls the “auth” microservice, which, based on the login, will determine which Keycloak realm the user belongs to and whether IDP is configured there.
  3. the "auth" service must redirect the user to the external IDP page, bypassing the Keycloak form, because the login form is provided on the front.
  4. after entering user data for external sso, an auth code will be returned, which must be exchanged for a token.
  5. redirect back to the original frontend page along with the jwt token, which will issue our Keycloak.

** I tried using the keycloak account client URL to go to the sso form, the Keycloak itself substitutes its URL in the redirect_uri and the authentication is successful, but this is not what I need, because the frontend already has a login form.

My question is: What should the link in step 3 look like, which the “auth” microservice will call in Keycloak? What needs to be inserted into the redirect - the original front URL, the Keycloak URL or the external sso endpoint? How can I return Keycloak token?

I compose it like this: {keycloakUrl}/realms/{realmName}/protocol/openid-connect/auth?client_id={clientId}&redirect_uri={???}&response_type=code&scope=openId&kc_idp_hint={alias}

Upvotes: 0

Views: 773

Answers (1)

ch4mp
ch4mp

Reputation: 12835

The solution you imagine goes against the current recommendations and breaks several OAuth2 rules.

frontend calls “bff” (backend for frontend) microservice, passing the user’s login as input

This is not how OAuth2 works. In OAuth2 authorization code flow, which is the only recommended flow for user login, neither the frontend nor your OAuth2 client should have access to users credentials. Only the authorization server does (in your case, Keycloak or the IDP behind it).

redirect the user to the external IDP page, bypassing the Keycloak form

With Keycloak, this is done by providing a kc_idp_hint parameter with the authorization request.

redirect back to the original frontend page along with the jwt token

According to the latest recommendations, OAuth2 tokens should not leave your servers. Communications between the front and back ends should be authorized with session cookies (and protection against CSRF). The BFF keeps tokens in session and replaces the session cookie with a Bearer token when forwarding requests. I wrote an article for that at Baeldung.

What you should do:

Provided that the BFF is a Spring Cloud Gateway instance:

  • define an OAuth2 client provider per realm
  • define an OAuht2 client registration with authorization_code for each "tenant" (a minimum of one per provider, more if you want Keycloak authentication plus some "direct access" to external IDP(s) for each realm)
  • expose an endpoint on the BFF listing the various options to initiate a login (one per registration)
  • the front-ends choose one of the options (either presenting choices to the user, "remembering" a previous choice, different instances deployed at different URLs configured each for a tenant, or whatever) and redirect the user agent to the right endpoint on the BFF which in turn redirects to the authorization server (which itself might redirect to an external IDP)
  • after the login is successful, the authorization server redirects the user agent back to the BFF with a code
  • the BFF exchanges the code for tokens and redirects the user agent back to the front-end
  • when routing a request from a front-end to a resource server, the TokenRelay= filter on the BFF replaces the session cookie with the Bearer token in session

I maintain a Spring Boot starter to help configure the BFF (protection against CSRF using cookies accessible to the front-end code, saving the post login/logout URLs in session, and more). Its usage is explained in the Baeldung article linked above.

Upvotes: 0

Related Questions