Learn Keycloak - OAuth 2.0 Scopes & Consent
Episode 8 of 31

Learn Keycloak - OAuth 2.0 Scopes & Consent

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.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Introduction

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.

What Is a Scope

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.

Standard OIDC Scopes

Some scopes are already available by default in a realm:

  • openid — marks the request as OIDC, triggering ID token issuance.
  • profile — profile claims like name, given_name, and family_name.
  • email — the email and email_verified claims.
  • offline_access — allows offline refresh tokens as in episode 7.
Requesting specific scopes
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.

Custom Scopes and Dynamic Scopes

Besides the built-in scopes, you can create your own client scopes:

  1. Open the Client scopes menu in the admin console, then Create client scope.
  2. Give it a name, e.g. user-details, and choose type Optional.
  3. Add protocol mappers to it — e.g. a mapper for a specific user attribute.
  4. Attach the client scope to the client in the Client scopes tab.

The result can be seen in the token payload:

Selected scopes in the access token
{
  "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.

Scope vs Role

Scopes and roles are often confused. They're both labels, but they sit in different positions:

AspectScopeRole
Question it answersWhat data can be accessed?What actions can be performed?
Decision holderUser via consentAdmin via role assignment
Location in KeycloakClient scopesRoles in realm or client
Appearance in tokenIn the scope claimIn 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.

Client Scopes: Default vs Optional

When configuring a client, the Client scopes tab has two attachment categories:

  • Default — automatically included every time the client requests a token, without needing an explicit call in the scope parameter.
  • Optional — only included when the client names the scope in the 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:

  • Via the account console — the user opens the Signing in menu, then Manage consent grants, and revokes applications they no longer want.
  • Via admin — an admin can remove a consent grant from the user's page in the admin console.
  • Via the login screen — Keycloak shows the consent screen again for permissions never approved before.

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.

Enforcing Scopes

A scope is only useful if it's enforced. On both the Keycloak side and the application side:

  • Client scope configuration — make sure sensitive client scopes don't land in the default list without a need.
  • Optional vs default — make non-essential data optional so users get a choice.
  • Audience restrictions — limit the token's aud to the right client via an Audience mapper, so tokens aren't used across applications beyond their intent.
  • Fine-grained permissions — for more detailed access control, use Keycloak's authorization services on top of roles and scopes.

Best Practices

Four habits that keep scopes healthy in production:

  • Principle of least privilege — give clients as little as possible: don't request scopes you don't need.
  • Clear scope descriptions — write a description for every client scope so it shows informatively on the consent screen.
  • User-friendly consent screen — recognizable client names and trust-building text.
  • Scope documentation — record which scopes each client has and why; this eases auditing.

Closing

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:

  • Scope answers "what data", role answers "what actions" — the two run side by side.
  • Default scopes should be frugal — make sensitive data optional so users get a choice.
  • Consent is user control — respect it and make the screen easy to understand.
  • Least privilege is the standard — clients request as little as possible, not whatever they want.

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.

Learn Keycloak - OAuth 2.0 Scopes & Consent | Learn SSO with Keycloak