Oidc-client-js: Silent login is not including the id_token_hint in the query string.

Created on 20 Nov 2016  路  9Comments  路  Source: IdentityModel/oidc-client-js

This is the application with which we are testing silent renew: https://zamboni-app.azurewebsites.net.

Login works as expected and results in two localStorage values:

Key: oidc.097c6062ed5547928aea963cc456607f
Value: {"id":"097c6062ed5547928aea963cc456607f","created":1479635448,"nonce":"9c51be022d7d4171a69e553ea3ad64e7","authority":"https://zamboni-auth.azurewebsites.net","client_id":"Aurelia.OpenIdConnect"}

Key: oidc.user:https://zamboni-auth.azurewebsites.net:Aurelia.OpenIdConnect
Value: {"id_token":"eyJhbGciOiJSUzI1NiIo...Gs5JtV5C_aBbA","access_token":"CfDJ8C4hTU...pMgdinWZcQYc","token_type":"Bearer","scope":"openid email profile roles","profile":{"unique_name":"[email protected]","AspNet.Identity.SecurityStamp":"2228d4ae-5865-4c22-80b8-8afcd140d0a3","sub":"b2618ce0-d2c1-49a9-90ac-a57191c18f9a","jti":"0b4f532d-19aa-4f3b-b46c-704833c470e2","usage":"id_token","azp":"Aurelia.OpenIdConnect"},"expires_at":1479635449}

When we do a silent login, the following request occurs, and it does not include the id_token_hint.

https://zamboni-auth.azurewebsites.net/connect/authorize
?client_id=Aurelia.OpenIdConnect
&redirect_uri=https%3A%2F%2Fzamboni-app.azurewebsites.net%2Fsignin-oidc
&response_type=id_token%20token
&scope=openid%20email%20roles%20profile
&state=6c48e3c0b728414f9d1adf2f5bc99a01
&nonce=8b576d7184f04f27bab43c5ea510cdf5
&prompt=none
question

All 9 comments

What does getUser() return for id_token?

This is what getUser() returns.

{  
   "id_token":"eyJhbGciOiJSUzI...Us9Q5YID0X06RjTdo7noKqHluiyvW1joAPsQKRQ",
   "access_token":"CfDJ8C4hTU...XDnlU",
   "token_type":"Bearer",
   "scope":"openid email profile roles",
   "profile":{  
      "unique_name":"[email protected]",
      "AspNet.Identity.SecurityStamp":"2228d4ae-5865-4c22-80b8-8afcd140d0a3",
      "sub":"b2618ce0-d2c1-49a9-90ac-a57191c18f9a",
      "jti":"bc05202c-2443-4fca-a45f-32e13a639a3a",
      "usage":"id_token",
      "azp":"Aurelia.OpenIdConnect"
   },
   "expires_at":1479751017
}

This is the full id_token:

eyJhbGciOiJSUzI1NiIsImtpZCI6IllaTElZQ1ZVVFBITlRIWVU0RUwwVEQ5WkNJUUJLODM4TUNKLTBSTVQiLCJ0eXAiOiJKV1QifQ.eyJ1bmlxdWVfbmFtZSI6InNoYXVuQGJpZ2ZvbnQuY2EiLCJBc3BOZXQuSWRlbnRpdHkuU2VjdXJpdHlTdGFtcCI6IjIyMjhkNGFlLTU4NjUtNGMyMi04MGI4LThhZmNkMTQwZDBhMyIsInN1YiI6ImIyNjE4Y2UwLWQyYzEtNDlhOS05MGFjLWE1NzE5MWMxOGY5YSIsImp0aSI6ImJjMDUyMDJjLTI0NDMtNGZjYS1hNDVmLTMyZTEzYTYzOWEzYSIsInVzYWdlIjoiaWRfdG9rZW4iLCJhdWQiOiJBdXJlbGlhLk9wZW5JZENvbm5lY3QiLCJub25jZSI6IjQwMWRiMmUzNjhhYzQ2ZTZhMjg5MDI0NmZkMjJmNGM4IiwiYXRfaGFzaCI6InBzOGFGYThVRWJNenl4YmRfOTBSV1EiLCJhenAiOiJBdXJlbGlhLk9wZW5JZENvbm5lY3QiLCJuYmYiOjE0Nzk3NTEwMDUsImV4cCI6MTQ3OTc1MTAzNSwiaWF0IjoxNDc5NzUxMDA1LCJpc3MiOiJodHRwczovL3phbWJvbmktYXV0aC5henVyZXdlYnNpdGVzLm5ldC8ifQ.LVLAAYFadwSp4nvij6IoKt8uJTwY2t6SnfU9xui2aMKfTbacDwI58xMOsplE8HvqOdMM5k6A_ucCmJ2DdrxfQkWSved_VZeF6Hwd07dMNU5f5uGsTXvAxWe67gWPp1eB5evSdtMTROgDBySluMxIUc9KAv_UW92GGZoRz5w26sR-EqQHtMyLDosKXPeA0kGMzT4ZwWerqPJnYVvzPFwMkEyLQiIGfLyH24TL0Wqj5rTBgXdebnWzvpM9162thGH9b1Haqluk6aLxOcieW6BeYGypjF3PZ1dN7AbwD7U1ZNrYsXiUs9Q5YID0X06RjTdo7noKqHluiyvW1joAPsQKRQ

This is the decoded id_token:

{
 alg: "RS256",
 kid: "YZLIYCVUTPHNTHYU4EL0TD9ZCIQBK838MCJ-0RMT",
 typ: "JWT"
}.
{
 unique_name: "[email protected]",
 AspNet.Identity.SecurityStamp: "2228d4ae-5865-4c22-80b8-8afcd140d0a3",
 sub: "b2618ce0-d2c1-49a9-90ac-a57191c18f9a",
 jti: "bc05202c-2443-4fca-a45f-32e13a639a3a",
 usage: "id_token",
 aud: "Aurelia.OpenIdConnect",
 nonce: "401db2e368ac46e6a2890246fd22f4c8",
 at_hash: "ps8aFa8UEbMzyxbd_90RWQ",
 azp: "Aurelia.OpenIdConnect",
 nbf: 1479751005,
 exp: 1479751035,
 iat: 1479751005,
 iss: "https://zamboni-auth.azurewebsites.net/"
}.
[signature]

At the time of attempting silent login, the current time is 1479751778, which means that the id_token has expired. I need to read the OpenID Connect specification to learn whether we can use an expired id_token as an id_token_hint.

This is the code that is calling getUser() to acquire the above data.

this.openIdConnect.userManager.getUser().then(function(t) {
    "undefined" != typeof t && null !== t && (t.expired ? e.loginSilent() : e.inMemoryUser = t)
})

I need to read the OpenID Connect specification to learn whether we can use an expired id_token as an id_token_hint.

You can.

As for expiration logic in the oidc-client library, we don't check expiration of the id_token when determining to send it or not. The expiration flags on the user have to do with the access token (not the id token).

I looked thru the code, and if you can see an id_token on the getUser(), then that should be passed when doing silent renews. You will need to debug further on your side.

I'll be adding some data points and [ hypotheses ] as they arise.

  • The silent login via iFrame works locally (localhost) and fails remotely (zamboni-app).
  • One difference is that running locally use HTTP while running remotely uses HTTPS.
  • [ Could getUser() in the iFrame context be looking for HTTP localStorage instead of HTTPS? ]
  • On the live site, using the dev build does not have the error, while the prod build does have it.
  • [ Is this is a JavaScript minification issue? ]

Thru debugging steps the issue has resolved and we are no longer able to reproduce it. It might have been a caching issue that kept delivering an older, broken release. Thank you for answering our questions along the way, especially that we can use an expired id_token as an id_token_hint.

@brockallen You wrote:

As for expiration logic in the oidc-client library, we don't check expiration of the id_token when determining to send it or not. The expiration flags on the user have to do with the access token (not the id token).

Thank you for clarifying that, and I have a follow up question to check my understanding. oidc-client-js validates the id_token once, and that is before adding it to web storage. After that, oidc-client-js does not need to re-validate the id_token. Now, if my-app (which is using oidc-client-js) decides to send the id_token to another component of my-app (e.g. a server-side component), then that component must validate the id_token before using the information in it. Is that right?

From the spec:

If any of the validation procedures defined in this document fail, any operations requiring the information that failed to correctly validate MUST be aborted and the information that failed to validate MUST NOT be used.

http://openid.net/specs/openid-connect-implicit-1_0.html#IDToken

From Google

One thing that makes ID tokens useful is that fact that you can pass them around different components of your app. These components can use an ID token as a lightweight authentication mechanism authenticating the app and the user. But before you can use the information in the ID token or rely on it as an assertion that the user has authenticated, you must validate it.

https://developers.google.com/identity/protocols/OpenIDConnect#validatinganidtoken

Thank you for clarifying that, and I have a follow up question to check my understanding. oidc-client-js validates the id_token once, and that is before adding it to web storage. After that, oidc-client-js does not need to re-validate the id_token.

Correct.

Now, if my-app (which is using oidc-client-js) decides to send the id_token to another component of my-app (e.g. a server-side component), then that component must validate the id_token before using the information in it. Is that right?

Yes, but this is not the normal use case for an id_token so I worry that this approach might get overused/abused. But how your server-side code does its validation is up to its threat model.

Thank you. We will be circumspect in our passing around of the id_token.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rmja picture rmja  路  3Comments

m-andrew-albright picture m-andrew-albright  路  5Comments

tomeinar picture tomeinar  路  3Comments

primozs picture primozs  路  3Comments

StephenRedd picture StephenRedd  路  5Comments