I was actually working on some IDP related stuff, so i was trying to do some POC and then i thought of writing this down.

Everyone would have been aware of “Login with Google/okta” etc, this writing isnt going to be explaining what really an IDP or Oauth2 is from a theoretical perspective, rather i will focus on explaining how typically things work between different services when IDPs or Oauth are involved

Some basics of OAuth2#

oauth2 is basically a set of rules should be followed in order to acheive this oauth2, it has some defined protocol/steps that lets any application to use the source application resources without needing to have separate accounts.

Some of the common terms of oauth2

  • Resource Owner: actual person, the user who is logging in.
  • Authorization Server: This is the identity provider, keycloak, google, okta etc…u can also build ur own.
  • Client: The application that asks the source application(which already has IDP)
  • Resource Server: Mostly the source application, who owns some of the protected APIs. eg: after google login, if the client asks google to get details of its drive, gmail etc.. then google is the resource server for client.

As said above oauth2 itself is just a spec/protocol.. things like keycloak, okta, auth0 etc are just implementations of this spec, OIDC(OpenID connect) adds one more layer which is basically the authentication part.

Now lets look at a real example,

Two companies, one login button#

Consider we have two companies companya and companyb, companya also uses companyb internally for some things companya manages its user using an IDP called keycloak, also companya doesnt want separate login flow for its users when they are trying to use companyb software, basically companya wants their own IDP to be used when using companyb, so that companya users can just use the same login and password.

Initially companya would have set it up their users already in keycloak, now if companya wants companyb to use the same IDP of their, then they need to first do the following

  • companya creates a client entry inside its Keycloak, typically informing IDP that a new client is onboarded, this client is basically companyb
  • companya generates a client_secret for the above client, and hands that secret to companyb(note this secret should only be known to companyb, and companyb should store this securely in their backend)
  • companya also puts companyb redirect URI, the url that keycloak will redirect after a login is successful.

How a login request actually flows#

Now comes the actual flow part, when companya users trying to access companyb software

  • companyb from their end they may have a typical login screen, where they may have a button Login with companyaIDP when a user press this button, companyb will basically redirect to companya IDP login screen, while redirecting companyb also appends client_id, redirect_uri and some state for verification.

  • now users login with their companya credentials as usual(companyb has no idea what are the creds and how this works), once its successful, the IDP automatically redirects to companyb redirect_uri with a temp code attached to the query string of the redirect_uri.

  • now companyb gets that code from the query string, and attaches its client_secret(the one that companya gives, after setting up the client) and calls /token endpoint of companya IDP provider, this endpoint will give back an id_token, the actual JWT secret.

  • the above JWT secret is the one, companyb can get the details of the user, this user details can be fetched via parsing the JWT token using companya IDP public key.

Why B can’t just trust the token blindly#

What actually proves the token is the signature part in the JWT token. And this is where asymmetric keys come in:

companya IDP provider has PRIVATE key and public key, signing the token is done by the private key and verifiying is done by the companyb using companya IDP public key

Where to get the public key from? an unauthenticated URL called the JWKS endpoint (JSON Web Key Set). It’s just a JSON file:

```json { “keys”: [ { “kid”: “abc123”, “kty”: “RSA”, “alg”: “RS256”, “n”: “xGOr-H7…”, “e”: “AQAB” } ] } ```

companyb fetches this public key using jwks endpoint and then decodes and verifies the JWT token.

Why this check needed? when token is created by companya IDP, it basically base64 the payload and signs that with RS256 and attaches that signature also in the token like base64(header).base64(payload).signature), you can literally get the payload without verifying itself, but this may break a huge security hole. consider a token is created with payload { role: sales } and its signed with RS256 with IDP private key, now consider an attacker changed this token to { role: admin } in the JWT payload part alone and sends, now if companyb decodes this without verifiying, we may actualy believed that he is admin and would have given admin privileges, but if we have did the verification it would have failed since the original signature is not associated with the new payload itself.

What is resource server here#

now consider after getting the token companyb further needs some other protected resource access from companya, in this case companyb would further call GET /api/resource to companya with the token that it already got and access the resources.

This is how a typical IDP based auth system works, and this example is written wrt keycloak in mind, but typically all IDPs work the same way endpoints can change, but concept remains exactly the same. You can also spin up ur own IDP system with all the rules followed from the oauth2 spec.

refer this sample repo, where i written keycloak based companya and companyb example