Use different scopes in your configuration access tokens

When you first subscribe to the Akamai Identity Cloud, you're given a configuration token policy. (If you’re setting up both Hosted Login and Webhooks v3, you're given two configuration token policies, one for each product.) These token policies include the following scope:

**.**

This is the “super admin” scope, the scope that gives the bearer full access to everything, or at least everything that requires a configuration token. Armed with this token, you can create, modify, and delete token policies and login policies and webhook subscriptions, and do just about any other administrative task you can think of.

If you’re OK with giving support personnel full control over everything, well, that’s up to you. As a best practice, however, Akamai recommends the “least privilege principle,” the notion that a user should only be given the permissions needed to do his or her job and nothing beyond that. If a support person has to read token policies then you need to give that person permission to read token policies. But what you don’t need to do is give them permission to modify token policies, or to delete login policies, or to read webhook subscriptions. Give users the permissions needed to do their job, and nothing beyond that.

The Akamai Identity Cloud is transitioning to the use of token authentication for administrative tasks; previously, administrative tasks (or at least the API calls used to perform administrative tasks) have relied on Basic authentication. Beginning with Hosted Login and Webhooks v3, however, the Identity Cloud is requiring bearer tokens: access tokens that are valid for one hour, and have been assigned a specific set (or sets) of permissions. These permissions are typically referred to as the token scopes.


📘

We should clarify one thing here: when we say “Hosted Login” we’re actually referring to the OpenID Connect (OIDC) Configuration APIs.


In this documentation we’ll walk you through different scopes that you can assign. We won’t explain how to assign these permissions; that’s something we do in the Hosted Login article Get started. But we will explain how you can configure scopes that do such things as:

  • Grant Access to Everything
  • Grant Access to a Subset of Things
  • Grant Access to Specific Things
  • Grant Read-Only Access to Things
  • Grant POST and PATCH Access to Things
  • Deny Access to Specific Items

Scope assignment terminology

Before we go much further we should define some of the terms used in this documentation. A scope, as we’ve already seen, represents permission to carry out an activity (read a login policy, delete a webhook subscription, create an OIDC client). A typical scope looks like this;

img

In this scope, config\loginPolicies represents the resource being managed (i.e., your OpenID Connect login policies).

Meanwhile, the asterisk (*) represents the behavior. The Identity Cloud supports four behaviors:

BehaviorDescription
*Grants full access to the resource. Because we’re dealing with APIs, that means access to the following endpoints:

GET
POST
PUT
PATCH
DELETE
+Grants “mutate and activate” permissions to the resource; that simply means that you can create new instances of the resource and make specific changes to the resource. However, you can’t view or delete the resource. Accessible endpoints are:

POST
PATCH
.Provides read-only access to the resource. Accessible endpoint:

GET
-Denies access to the resource. Because access is denied, none of the resource endpoints are accessible

📘

And the colon (:)? That’s just a way to separate the behavior from the resource.


You’ll also see scopes that look like this:

*:config/**

In those cases, the double asterisk (**) means that any child namespaces are also covered by the permissions. In other words, *:config/* grants full access to the config namespace as well as all its child namespaces: config/clients; config/tokenPolicies; config/loginPolicies.


A quick note about scope assignment

The scopes that can be assigned to a configuration token are based on the allowedScopes property found in the associated token policy. For example, a token policy might include this value:

"allowedScopes": [
    "openid",
    "+:**",
   ".:**",
    "*:**",
    "*:config/tokenPolicies",
    "-:config/tokenPolicies/8cdb3f99-ceee-403d-a01d-daf392e18350"
 ],

Without going into the particulars (which we’ll cover in the rest of this documentation), this token policy can be used to grant six different scopes:

  • openid
  • +:**
  • .:**
  • *:**
  • *:config/tokenPolicies
  • -:config/tokenPolicies/8cdb3f99-ceee-403d-a01d-daf392e18350

However, when you request a token from the token endpoint, it might look like you can request scopes that aren’t specified in the token policy. For example, here we’ve requested the *:config\loginPolicies scope, a scope not found in the token policy. In turn, our request completes without an error, and we're granted an access token:

img

But here’s the thing: the token we’ve been granted isn't of much use. How do we know that? Well, for one thing, when we get back a token we should also get back information about the scopes we’ve been granted:

img

But notice that, for the token we just received, no scopes are listed:

img

That means that the token exists, but it hasn’t been granted any permissions; that makes the token pretty much useless. The moral of this little story? Any time you request an access token, make sure you're also given the scopes you asked for. If no scopes are returned:

  • Verify that you entered the scope names correctly; for example, you might have typed *.config\tokenPolicy instead of *.config\tokenPolicies.

  • If you’re confident that you entered the scopes correctly, check the token policy to verify that the scopes actually appear in that policy.

Oh, and when we said the preceding token was useless, we meant it. No matter what we try doing with that token, access is going to be denied:

img


Grant access to everything

As noted at the beginning of this documentation, the *.** scope provides a user with full access to everything; as such, you should exercise caution when assigning this scope. Nonetheless, it’s available if and when you need it. You can also use these two scopes to give full access only to the OIDC Configuration APIs or only to the Webhooks v3 APIs, respectively:

  • *:config/**
  • *:webhooks/**

One thing to keep in mind is this: giving someone the *:webhooks/** scope will give that user full access to webhook subscriptions and webhook events. What it won’t do, however, is allow this user to access the configuration client or the token policy used to manage Webhooks v3. Why not? Because those items are part of the config namespace:

  • config/clients
  • config/tokenPolicies

To give a user access to the configuration, the token policy, and to webhook subscriptions and events you’ll need to assign them the *.** scope.


Grant access to a subset of things

As noted in the previous section, you can create scopes that provide access to the OIDC Configuration APIs or to the Webhooks v3 APIs but not to both. In other words;

*.config/**
*.webhooks/**

If you want, however, you can get even more granular by limiting access to specific namespaces. For example, the OIDC Configuration APIs include the following namespaces:

  • config/clients
  • config/loginPolicies
  • config/tokenPolicies

Likewise, Webhooks v3 includes these namespaces:

  • webhooks/subscriptions
  • webhooks/events

Want to give someone full access to your webhook subscriptions but not give them access to the events captured by those subscriptions? Then assign them the following scope:

*:webhooks/subscriptions

Incidentally, you can assign users multiple scopes. For example, the following scopes give a user full access to token policies, login policies, and webhook subscriptions:

*:config/tokenPolicies
*:config/loginPolicies
*:webhooks/subscriptions

Of course, there is a potential problem here: if you assign multiple scopes to a user you run the risk of encountering a permissions conflict. For example, suppose you inadvertently assign a user a scope that grants full access to your token policies and, at the same time, assign a second scope that denies access to the token policies:

img

In a case like that, the deny scope prevails, and the user is denied access to the token policies:

img

For those of you scoring at home, in case of a conflict full access (*) overrides mutate/activate access (+) which overrides read-only access (.). But deny access (-) overrides everything:

Permission 1Permission 2Which Permission “Wins?”
Full accessMutate/activateFull access
Full accessRead accessFull access
Full accessDeny accessDeny access
Mutate/activateRead accessMutate/activate
Mutate/activateDeny accessDeny access
Read accessDeny accessDeny access

Grant access to specific items

If you want to get really granular, you can limit a user’s access to an individual item. For example, suppose you’d like one of your support people to have full access to one thing and one thing only: token policy 8cdb3f99-ceee-403d-a01d-daf392e18350. If that’s the case, just assign the user a scope similar to this one:

*:config/tokenPolicies/8cdb3f99-ceee-403d-a01d-daf392e18350

With that scope, the user will be able to view, modify, and even delete token policy 8cdb3f99-ceee-403d-a01d-daf392e18350. However, the user won’t be able to read or modify any other token policies, nor will they be able to create a new token policy.


Grant read-only access to things

Often-times support personnel benefit from being able to view something even if they aren’t allowed to change that thing. For example, if users keep getting an invalid client error whenever they make a Hosted Login authorization request, a support person could check the redirectURIs property assigned to the OIDC client to see which pages the client can redirect to. If webhook notifications aren't showing up, a support person can check the properties of the webhook subscription to verify that the endpoint URL is correct. With read-only access support personnel can make these kinds of checks; they just won't be able to change any of the items they're looking at.

To grant read-only access to something, use the . behavior. For example, do you want someone to have the right to read webhook subscriptions, but not to create, modify, or delete webhook subscriptions? Then issue that person a token similar to this:

.:webhooks/subscriptions

If you use that token, and the GET method, you’ll get back a list of all your webhook subscriptions:

img

But if you try to create a new subscription, well, it’s simply not gonna happen:

img


Grant POST and PATCH access to things

Admittedly, this might be a bit more arcane, but it’s possible (using the + behavior) to give someone the right to use the POST method and the PATCH method but nothing else. Among other things, that means that this user has permission to create new login policies, even though he or she won't be allowed to view those policies after they've been created.


📘

In case you were wondering, at this point in time the PATCH method can only be used to modify webhook subscriptions. Everything else requires the PUT method, a method not allowed with the + behavior.


For example, here’s the syntax for giving someone “mutate and activate” permissions to login policies:

+:config\loginPolicies

If you get an access token with this scope, you’ll be able to create a new login policy, an action that returns the ID of the new policy:

img

But even though you created the policy, you won’t be allowed to use the GET method to view policy information:

img

Weird, but true!


Deny access to specific items

At first glance, you might wonder why you even need to do this. For example, suppose you want to allow someone to be able access token policies and login polices, but not allow them to access information about OIDC clients? That’s fine; just issue them a token that leaves out OIDC clients altogether:

*:config/tokenPolicies
*:config/loginPolicies

But suppose you wanted to give this user the right to access all your token policies except for one particular policy. Within a single administrative category, is it possible to provide access to most things, but not to all things? As it turns out, it’s very possible.


📘

Why would you want to do something like that? Well, for one thing, you might set up a token policy with all your allowed scopes and then want to make that policy off-limits to most administrator. That way. you’ll always have a full token policy on hand should some sort of disaster (intentional or unintentional) wipe out your other token policies.


Let’s suppose we have a user who needs access to token policies, but who should not have access to one particular policy (policy ID 8cdb3f99-ceee-403d-a01d-daf392e18350). In that case, we need to issue the user a token that has the following scopes:

*:config/tokenPolicies
-:config/tokenPolicies/8cdb3f99-ceee-403d-a01d-daf392e1835

The first scope provides full access to all the token policies; as you know, the * behavior is for complete access. The second scope explicitly denies access to the token policy with the policy ID 8cdb3f99-ceee-403d-a01d-daf392e18350; the behavior prevents access to the specified object.

So, will this really work? Let’s find out. First, we’ll try to retrieve all the token policies. Here’s what we get back:

img

If you look at the first item in the list, you’ll see the “forbidden” token policy (policy 8cdb3f99-ceee-403d-a01d-daf392e18350). That means that we know that the policy exists. But if we now make a second API call, one that tries to retrieves the property values of that policy, well, this is what happens:

img

Even though we have full administrative rights to token policies, we can’t even get read-only access to that one policy. If we try any other policy we’ll get back the expected information:

img

But we won’t have access to 8cdb3f99-ceee-403d-a01d-daf392e1