Add scopes to a token policy

Adding a Scope to a Token Policy


Scopes make it easy to automatically return user information following a successful Hosted Login authentication. For example, suppose you’re interested in returning address information for users. In that case, you might want to add the address scope to your authentication request; that causes Hosted Login to retrieve the following claims (a single piece of user data) from the user’s user profile and then make those claims accessible from the userinfo endpoint:

  • country (primaryAddress.country)
  • locality (primaryAddress.city)
  • postal_code (primaryAddress.zip)
  • region (primaryAddress.stateAbbreviation)
  • street_address (primaryAddress.address1, primaryAddress.address2)

📘

The boldfaced items in the preceding list indicate the name of the Identity Cloud user profile attribute associated with the claim.

Or at least this usually causes Hosted Login to retrieve claims from the user profile and make them accessible from the userinfo endpoint. In real life, however, you might run into a situation where you ask for something (i.e., a specific scope or set of scopes) and Hosted Login declines to give it to you. In this article, we’ll explain how that situation might arise, and then give you some pointers on what you can do if it does arise.

To make it easier to follow what we’re talking about, we’ll use the Identity Cloud’s OpenID Connect Playground, a website that (among other things) makes it a cinch to add scopes to an OIDC authorization request. For example, in the following screenshot we’ve assigned two scopes to the request, openid (which must be included in all OIDC authorization requests) and address, which returns information about the user’s physical address (street address, city, state, country, etc.):

And before you ask, yes, that did add both of those scopes to our authorization request:

📘

The preceding screenshot shows how you add scopes if you aren’t using the OIDC Playground to create authorization requests. To add a scope, just use the scope parameter followed by a list of the scopes you'd like to get back, making sure to separate the individual scopes with a blank space:

scope=openid address email profile

After making the authorization request and logging on, we make a call to the userinfo endpoint to verify that the address information is available from there. And, lo and behold, it … uh, isn’t:

As you can see, no address information was returned from the user info endpoint.

Fortunately, we know exactly what the problem is. In our authorization request we asked to get back address information. But, just like in the non-OIDC world, you don’t always get what you ask for. In this case, at least, there’s a good reason why we didn’t get what we asked for. In an authorization request, you can request any scopes you want. However, that doesn’t mean that you’ll get back each of those scopes. That’s because the scopes you can get back depend on the allowedScopes property in the token policy associated with your OIDC login client. If we use the Identity Cloud’s OpenID Connect Configuration APIs to examine the relevant token policy, we’ll see that address is not included in the allowedScopes property:

{
   "id": "a7f902b3-6e63-4f60-87a6-6cf5a1bc8ff4",
   "accessTokenLifetime": 3600,
    "allowedScopes": [
        "openid",
        "profile"
    ],
    "refreshTokenLifetime": 7776000,
   "title": "GREG_DEMO Token Policy",
   "_links": {
       "self": {
           "href": "/config/e0a70b4f-1eef-4856-bcdb-f050fee66aae/tokenPolicies/a7f902b3-6e63-4f60-87a6-6cf5a1bc8ff4"\
      }
   }
}

Because the token policy takes precedence over the authorization request, our bid to get back the address scope is denied. Bottom-line: if it’s not in the token policy it’s not coming back.

And no, you don't get an error: you just don't get the information you requested.

On the surface, this might seem a bit odd: why does the token policy dictate the scopes you can get back? If you think about it, however, this actually makes sense. After all, tokens are the currency used to power Hosted Login transactions. For example, if you want to access your user profile you need to present a token that has been granted access to that profile; if you don’t have the right token then you can’t access the user profile (regardless of whether or not that profile belongs to you). Because tokens determine what you can and cannot do, common-sense (and recognized standards) suggest that your access rights should be determined by your token policy.

And that's fine: if the fact that your token policy doesn’t allow the address scope is the worst news you get today then you’re probably having a pretty good day. That's because it’s easy to add the address scope to your policy: all you have to do is use the /config/tokenPolicies/{tokenPolicyId} endpoint to append address to the set of allowed scopes.

Before we do that, however, a word of warning. Like other OpenID Connect Configuration APIs, the /config/tokenPolicies/{token_policy_id} PUT method replaces the entire property set of the token policy with the properties and property values included in your API call. That means that all of the token policy properties and property values must be included in your PUT call, even if you’re only changing the allowedScopes property.

To help you deal with this requirement, we recommend that you first use the GET method to return the current properties of the policy, then copy those properties and property values and paste them into the body parameter of your API call. After you’ve done that, you can change property values, like we’re about to do right now.

To add a new scope to your token policy, all you have to do is add that scope to the allowedScopes property:

"allowedScopes": [
   "openid"
   "profile",
    "address"
],

You say you also want the option of getting back the email scope? That’s fine; simply add that scope to the allowedScopes property as well:

"allowedScopes": [
   "openid",
   "profile",
    "address",
    "email"
],

Just make sure that each scope name is enclosed in double quotes, and that you use proper JSON (JavaScript Object notation) when formatting your API call.

Here’s what a complete API call looks like in Curl:

curl -X PUT \
  'https://v1.api.us.janrain.com/e0a70b4f-1eef-4856-bcdb-f050fee66aae/config/tokenPolicies/a7f902b3-6e63-4f60-87a6-6cf5a1bc8ff4' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer t19K0gt1U-MaCDcHSHs0Q_cVgxEy-gLZRjkYs3oAG3ODHnwyiCDK22PxZka4Wip4' \
  -d '{
    "id": "a7f902b3-6e63-4f60-87a6-6cf5a1bc8ff4",
    "accessTokenLifetime": 3600,
    "allowedScopes": [
        "openid",
        "profile",
        "address"
    ],
    "refreshTokenLifetime": 7776000,
    "title": "GREG_DEMO Token Policy"
}'

So now, armed with an updated token policy (that is, one the allows the address scope), let’s use the same authorization request we created a little while ago and log on. After we’ve been authenticated, we make a call to the userinfo endpoint, and guess what we find there:

Mission accomplished.