Id_token vs. access_token to propagate authentication

I am using the OIDC flow with id_token for authentication. This is an server-side MVC app using Authorization Code flow.

Once a user is logged in, I want to propagate authentication context to microservices in the same application. Those services are accessed through HTTP endpoints, back-end to back-end.

What’s the best practice to solve this? The two alternatives I can think of are:

  • Pass the id_token itself in HTTP headers, and the recipient validates its signature and expiration.

    • Pros: convenient.
    • Cons: everything I’ve found on the topic (mostly for other products) says not to do this.
  • Pass the access_token in HTTP headers, and the recipient uses the access token to call the Okta /userinfo endpoint.

    • Pros: more consistent with standards.
    • Cons: not clear why this is better than passing the id_token itself. It feels awkward because breaking up my application into multiple microservices is an implementation decision internal to my app, not creating a concept of a “resource server”. And there is no concept of the user authorizing component A to call component B on their behalf; component B just needs to know which user is logged into component A.
  • Pass the access_token in HTTP headers. Recipient validates the token and gets claims off of it directly.

    • Pros: as convenient as id_token
    • Cons: not standards-compliant – OIDC spec does not require access tokens to be JWT; access tokens can be opaque.
2 Likes

Hey @wrschneider,

From a very practical perspective, I think passing the access token is better, since you can always get the user info given the access token (but not the other way around). It does have the benefit of being more spec compliant as well. :slight_smile:

If the user info needed at your microservice layer is small (just the sub claim, for example), I think #3 would be the best choice. When you create a custom authorization server in Okta, you have a lot of control over which claims are included in access tokens, so you could ensure all your tokens have the info you need.

You’re right that the access tokens are not guaranteed to be JWTs. We don’t have any plans to switch our access tokens to opaque tokens, but even if we did, you could still make an introspection request to see the access token’s claims.

If I’m going to validate and take claims off the access token directly, why is that better than using the ID token for the same? What would break, or what vulnerability would I create, if I used the ID token for that?

2 Likes

hi @wrschneider, what option did you finally select? I have a very similar architecture as you described.

I am going with id_token for authentication, access_token for authorization.

API that receives the access_token can obtain user information by validating the claims on the access_token directly via signature, or by calling Okta APIs with the access token.

The distinction is subtle and doing this mostly because access_token for API calls seems more standards-compliant, and does not make assumptions about how the user was authenticated. An id_token is coupled to an OIDC authentication flow.

However, from the client’s perspective, getting an access_token and id_token at the same time is a good reason to use OIDC flows for authentication vs. SAML.

1 Like

@wrschneider
I am getting error with introspect

My Post url:

https://navi-2020.okta.com/oauth2/default/v1/introspect?client_id=0oa57fbt3r5I638u94x6&token=eyJraWQiOiJDM3ExbXRzdFY4U0tUTjZTY09jRkFjeXNDckNKRDI0N1NtQkMtM2dGd1hzIiwiYWxnIjoiUlMyNTYifQ.eyJ2ZXIiOjEsImp0aSI6IkFULnE4ZWc1Vk1NMjZ1LWMxai1URFM1RGp4X0hwN1VXUS1sQXFfNkp3eTlFSG8iLCJpc3MiOiJodHRwczovL25hdmktMjAyMC5va3RhLmNvbS9vYXV0aDIvZGVmYXVsdCIsImF1ZCI6ImFwaTovL2RlZmF1bHQiLCJpYXQiOjE1ODYwOTQ2NzcsImV4cCI6MTU4NjA5ODI3NywiY2lkIjoiMG9hNTdmYnQzcjVJNjM4dTk0eDYiLCJ1aWQiOiIwMHU1NjV3djNFTkZFUTFRWTR4NiIsInNjcCI6WyJwcm9maWxlIiwib3BlbmlkIiwiZW1haWwiXSwic3ViIjoia3VtYXIuc2h1YmhhbUBuYXZpLmNvbSJ9.HAXhUsxsANRl_QsKU7A--9qP3KFJDSfk5eDFlfnAdVCZREmcI7OF465J0dFJJxbo2BCCLlwFSLdoK4glu7DEt2gIv9rLldN82m1WzdAH95f4BnXQOKCfn1apAVQyUpkNap_TrvxdW-id-QQWB2_nNso815f5eEO0GhUug3ZC5yIdwRQudjAw1oUQR0i1EVNBhROK_GHrnz7W25PVj_MPGfk8GfbCP7ZuBhK30-UjhvGx6O7Fg1w0vOjSYY1ta4WmQoGVYykNGB_ISvkSqBgCeh2_pjIY3BALjTXQOzEauAkyZjyft7lS70naAchVhsK3mfsxxnDq2VUx6zCY3KIDIQ&token_type_hint=access_token

error:
{
“errorCode”: “E0000021”,
“errorSummary”: “Bad request. Accept and/or Content-Type headers likely do not match supported values.”,
“errorLink”: “E0000021”,
“errorId”: “oaeQ-E3aTk-T9KSb5xJIZKhzg”,
“errorCauses”: []
}

Please help.
Thank You.

Hi @Shubham6541

The error occurs when Accept and Content-Type headers are not added or have an invalid value. Here is a small cURL example for using the introspect endpoint.

curl --location --request POST 'https://dragos.okta.com/oauth2/default/v1/introspect' \
--header 'Accept: application/json' \
--header 'Authorization: Basic MG9hN...' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'token=TOKEN'

@dragos Thank you, it helped.
One more thing, how can i use okta-spring-boot-starter to make remote validation using introspect for org authorization server.
I used spring-security-oauth, but getting unauthorized even when it is legal token.

Please help.
Thanx in advance.

Hi @Shubham6541

The unauthorized error means that the authorization credentials are incorrect. Can you please check that you are sending the authorization header and that it contains a value based on the following formula?

base64_encode(client_id + ":" + client_secret) 

If you have only client ID for the OIDC app in Okta (eg. if using a SPA or native app), can you please remove the authorization header and send the client ID in the request body, along with token?

@dragos Actually, I am able to validate the token from curl or postman. There it is authorizing correctly. But, I am unable to verify it from spring boot. What dependecies I should use to validate the token.

Current Scenario: I am using SPA, Having react as client application and spring-boot as server. Sending token from client side to server side. But, I am not able to validate that token. I am using org authoriztion server. So, I have to use /introspect to validate the token. That I am not able to figure it out, how to use introspect to validate the token.

dependencies I am using:
"
org.springframework.boot
spring-boot-starter-security


org.springframework.security.oauth
spring-security-oauth2
2.2.0.RELEASE

"
application.properties:
security.oauth2.client.clientId=0oa57fbt3r5I638u94x6
security.oauth2.resource.tokenInfoUri= https://navi-2020.okta.com/oauth2/v1/introspect

@dragos Please look at it.