"id_token" missing in "/oath/token" response when Rule adds custom scope to "context.accessToken"

Hi,

I am playing with a Rule that adds a custom scope to the accessToken. I am using the Authorization Token Flow, and I have noticed that the idToken is not returned from the /oath/token endpoint when this rule runs. The rule is very simple:

function(user, context, callback){
  context.accessToken.scope = context.accessToken.scope || [];
  context.accessToken.scope.push('werwer');
  callback(null, user, context);
}

It is the only rule in the pipeline.

The /oath/token response payload looks like this:

{
  "access_token": "tokentokentoken",
   "expires_in": 86400,
   "scope": "werwer",
   "token_type": "Bearer"
}

This behavior is the same whether or not I pass an API name as audience. I wondered if this might have something to do with the “OIDC Conformant” setting on my Application, but after turning that off, I get the same behavior.

Any help? Thanks!

Aside: Seems related to this issue, but not an exact match: IDToken not returned when additional scopes are defined

Hi :wave: @atorgerson, welcome to the community!

This is a complete shot in the dark, but what’s the response_type you’re requesting? I believe it should be code id_token. (Note the blank space)

1 Like

Thanks @thijmen96. I tried that and it didn’t quite have the result I was expecting. I’m using the “Authorization Code Flow”, so I’m used to the id_token being returned from the /oath/code endpoint, and the redirect query string having only the authorization code in it (&code=XXX).

Passing response_type=code+id_token causes the id_token to be included in the callback URL query string: code=XXX&id_token=YYYYY (I had to include a nonce=ZZZ query param as well - endpoint returns an error without that). I suppose that does achieve the outcome I’m seeking (actually receive the id_token somehow), it’s just not how I understand the “Authorization Code Flow” to work.

My underlying question, however, is why? Why does simply touching the scope in a rule cause the id_token to be omitted from the response? I played with my rule, just commenting out the part that adds an item to the scope array, leaving the part that initializes the scope as an array, and even just that causes the /oath/token response to omit the id_token.

function(user, context, callback){
  context.accessToken.scope = context.accessToken.scope || [];
  callback(null, user, context);
}

/oath/token response:

{
  "access_token": "<munged>", 
  "token_type": "Bearer", 
  "expires_in": 86400
}

Really scratching my head here.

Yeah it’s not just you. I’m using a username password authentication from a highly trusted app. The refresh and id token were working fine. Then I added a rule to add additional scopes and the id token and refresh token quit returning, only the access token.

Ok right after I posted this I realized that I’m replacing the scopes that were requested. So adding the openid and offline_access back into the scope fixed this.
Is there a way to see the scopes that were requested and add them back?

1 Like

Ahhh! Excellent observation - I have the same question - where can the requested scopes be found? I was trying to preserve them by only assigning context.accessToken.scope if it was undefined, but it seems as those requested scope values ought to be there already.

Alright, I think I found the solution, thanks to @jon.roberts observation of the missing openid scope.

This snippet preserves the requested scopes.

function(user, context, callback){
  var requestedScopes = context.request.query.scope;
  if (requestedScopes) {
    requestedScopes = requestedScopes.split(' ');
  } else {
    requestedScopes = [];
  }
  
  // TODO: probably aught to preserve any scopes already added in previous rules, rather than blindly overwrite.
  context.accessToken.scope = requestedScopes.concat(['array', 'of', 'strings']);
  callback(null, user, context);
}

Perfect! Thanks.

Also, probably best not to just blindly return any requested scopes either, but that probably depends on your app.

1 Like

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.