Valid values for Authorization Scopes?

What are valid values for authorization scopes? I can see in examples “view, modify, create, write”. I can see them also like “account:read or account:modify”. What is the difference?
Can I choose them freely? Do they need to match a http verb?

TL;DR: you can choose freely, no need to match any http verb. :slight_smile:

The following is something I wrote some time ago while trying to make sense of the policy / permissions / scope model of Keycloak. It’s the “scope” part.

rfc6749 (ietf.org) section 3.3

Scope is difficult to understand, because, contrary to policies and permissions, it does not have a structure to guide the configuration. In Keycloak a scope is nothing more than a identifier (string, friendly name), which is then used by permissions, resources etc.

Historically, scopes are used to define batch privileges from one app to another. Typically, when adding a new service to Twitter, Twitter will provide access to scopes: can the user use this service to post messages, to read, etc. So, scopes are as fine-grained as the user requires, no more and no less. So, the precision of a scope is arbitrary, it can be whatever makes sense to whoever is managing privileges.

Generally the name of a scope is the combination of an action and a subset of the resource info model . (examples: takeMoneyFromAccount, readFile, sendMessages, root_readwrite, …)

A scope is actually an aspect of a resource, often expressed as an action. A scope is akin to an interface in object-oriented modelling. In other words, scopes are like tags added to resources to indicate whether they are concerned with a particular type of privileges .

In Keycloak, a scope does not reference resources. Even a scope called “writeFile” will not reference the resource type “file”, it is up to each resource “file” to specify that it supports the scope “writeFile”. However, when evaluating access (permit/deny), Keycloak can search for all resources with a given scope, and permissions can be granted on all resources with a given scope. So de facto navigation is possible from scope to resources.

Made-up example:

  • scope “takeMoneyFromBankAccount”. It is expressed, as stated above, as a combination of action and subset of our info model.
    • “take” is our friendly name for an action
      • the word “take” may not appear anywhere else, it’s just the friendly name for the operation, or operations, covered by this scope.
      • if it was an OO interface, it would be “takeable”, which makes sense: this scope does not indicate a privilege, but a possibility, the scope may be denied for some users. It means that for this resource, taking money makes sense.
    • “money of a bank account” is our subset of the info model.
      • it could be the attribute “balance” from a resource type “bankAccount”
      • “of a bank account” will actually be enforced by only setting this scope on resources of type bankAccount
    • this scope can be useful, because it excludes: creation, deletion etc of bank accounts, operation on user profiles or other resources,…
    • this scope is not useful if it’s the same set of privileges to take money or put it (credit/debit). In that case it’s better to define a scope called “manipulateMoney”.

Some examples of usage in the real world:

  • From the Slack API OAuth Permission scopes | Slack
    • scopes are described as the subsets of privileges that you can authorize or not for another app. For example, AnvilCorp wants to access your slack, can it “send messages”, can it “access info about your public channels” ? These are scopes.
  • From an API example Scopes - Box Developer Documentation : “The name for a set of permissions for an application is a “scope”.”
    • example: root_readwrite, root being the top dir, readwrite being operations. So it’s a kind of combination between a relevant subset of the resource (here the root dir) and a subset of actions (read and write).

Once a scope is defined, all resources should be scoped or not. For example, if the scope read and write are chosen, all resources that can be read or write should be declared as such using their scope, otherwise permissions will not find them. This means that scopes are an important part of a resource definition. If a resource does not have a scope, it should be a decision, not an oversight.

Yet another example: in a garden, resources are all plants. Plants include edible fruit, that can be sold, and flowers, that stay for decoration. There is a scope “forSale” that represents an aspect of a plant. This could also be named “sellPlant” (action and subset of info model), or “sellable” (OO design). Some plants do not have that scope, as they are not for sale. Gardeners can have access over all resources, vendors can have access over scope, which will restrict de facto their access to sellable plants, marketers can change the prices of sellable items, others can only read it… so we could have the permissions “setPrice” and “getPrice” that are only effective on sellable items. It is possible later to stop sales on some fruit, or start selling some flowers, by changing the resource scopes.

Note that “read” and “write” are often used as examples of scopes. That is misleading: scopes are not verbs, but packages of privileges that are attached to the resources. A way of looking at this is to consider a filesystem: “read” scope may cover several operations, such as listing contents of a (“cat file”), opening it (in read mode), getting its info (“ls -l”), and may even exclude some protected files.

1 Like

Thank you very much for the explanations. Very useful.
But when we use policy enforcerer we have to specify in the application.xml file:

keycloak.policy-enforcer-config.paths[0].path=/customers/*
keycloak.policy-enforcer-config.paths[0].methods[0].method=GET
keycloak.policy-enforcer-config.paths[0].methods[0].scopes[0]=view
keycloak.policy-enforcer-config.paths[0].methods[1].method=POST
keycloak.policy-enforcer-config.paths[0].methods[1].scopes[0]=create

Does the scope need to match the http verb?