Understanding the role of scopes in OAuth 2.0 and Keycloak: standard and custom scopes, default vs optional client scopes, the consent screen flow, and best practices for applying the principle of least privilege in applications.

In episode 7 you managed tokens: refresh, rotation, and revocation. Episode 8 answers a more fundamental question: what data may an application take from a user's account, and who decides? The answer lies in two interrelated OAuth 2.0 mechanisms — scope to limit the request, and consent for user approval.
A scope is a permission-request label the application sends when requesting a token. When an app requests profile, it's saying: "I need the user's profile data". Keycloak then maps that scope to a set of claims via protocol mappers.
In Keycloak, scopes aren't declared one by one inside a client; instead they're wrapped as client scopes — collections of mappers reusable across many clients. A client simply points to the client scopes it needs.
Some scopes are already available by default in a realm:
name, given_name, and family_name.email and email_verified claims.curl -X POST "https://kc.example.com/realms/my-realm/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "client_id=my-app" \
-d "client_secret=4f9a2c8d..." \
-d "code=1c2a3b..." \
-d "redirect_uri=https://app.example.com/callback" \
-d "scope=openid profile email"The scope=openid profile email above requests three scopes at once. Note that openid is always required for OIDC flows — without it, Keycloak won't issue an ID token.
Besides the built-in scopes, you can create your own client scopes:
user-details, and choose type Optional.The result can be seen in the token payload:
{
"scope": "openid profile email user-details",
"preferred_username": "budi",
"department": "engineering"
}Keycloak also supports dynamic scopes — scopes that carry dynamic values, like number_format:ID or language:ja, which trigger special mappers in the realm. This feature is enabled in Realm settings and suits services that need parameterized scopes, such as document printing or translation.
Scopes and roles are often confused. They're both labels, but they sit in different positions:
| Aspect | Scope | Role |
|---|---|---|
| Question it answers | What data can be accessed? | What actions can be performed? |
| Decision holder | User via consent | Admin via role assignment |
| Location in Keycloak | Client scopes | Roles in realm or client |
| Appearance in token | In the scope claim | In realm_access or resource_access |
The analogy: a scope is the permission to view a document, a role is the permission to sign it. Applications need both working together.
When configuring a client, the Client scopes tab has two attachment categories:
scope parameter.scope parameter.A common pattern: put openid, profile, and email as default, and make scopes carrying sensitive data optional. That way, clients that don't need that data won't get it silently.
When a client ticks Consent required, Keycloak shows a consent screen after a successful login. On that screen the user sees the list of requested permissions — e.g. "View your email" and "View your profile" — and chooses Yes or No. This is the moment where the user holds control over their own data.
Tip
The title and description on the consent screen come from client attributes set in the Settings tab — specifically Display name and Consent screen text. Write clear, honest descriptions; confused users will decline or, worse, click through blindly.
The consent flow runs only once per user and client as long as the grant remains valid. Once the user approves, subsequent requests are considered already authorized — Keycloak calls that client pre-authorized for that user. If you want a specific UI consistency or for a fully trusted internal client, there are settings to skip the consent screen entirely.
Consent isn't a once-and-forever decision. Users can revoke it at any time:
After consent is revoked, the client must ask for permission again on the next visit — the same effect as logout, but scoped to data access.
A scope is only useful if it's enforced. On both the Keycloak side and the application side:
aud to the right client via an Audience mapper, so tokens aren't used across applications beyond their intent.Four habits that keep scopes healthy in production:
In episode 8 you understood scopes and consent: the definition of scope and client scope, standard OIDC scopes, custom and dynamic scopes, the difference between scopes and roles, default vs optional client scopes, the consent screen flow, consent management by users and admins, and enforcement and best practices.
Key takeaways:
In the next episode (episode 9) we step up to the layer above OAuth 2.0: OpenID Connect — the protocol that turns pure authorization into standardized authentication with the ID token and discovery mechanism.