Default vs. Optional Client Scopes in Keycloak
The quiet setting that decides whether a piece of user data rides along in every single token, or only shows up when an application specifically asks for it.
Every token Keycloak issues is a small, carefully curated bundle of information — a user’s identity claims, their roles, sometimes their phone number or offline access rights. But how does Keycloak decide exactly what to put inside that bundle for a given application? The answer lives in a feature called Client Scopes, and specifically in the distinction between Default and Optional Client Scopes. This single distinction — whether something is baked into every token automatically, or only added when explicitly requested — has real consequences for token size, application design, user consent, and security posture. This guide walks through exactly how Default and Optional Client Scopes work, how they differ, and how to use each one deliberately and well.
ACore Concepts: What Are Client Scopes, and How Do Default and Optional Differ?
A Client Scope in Keycloak is a named, reusable bundle of configuration — primarily Protocol Mappers (rules that decide which claims get written into a token) and, in some cases, Role Scope Mappings — that can be attached to one or many Clients. Instead of configuring “include the user’s email in the token” separately for every single application, an administrator defines that behavior once, inside a Client Scope named something like email, and then simply attaches that scope to whichever Clients need it.
Once a Client Scope exists, it can be assigned to a specific Client in one of two ways, and this is exactly where our central distinction lives:
Always Included
Automatically applied to every token issued to that Client, with no need for the application to request it explicitly in the authorization request.
Included Only on Request
Only applied if the application explicitly asks for it by name, typically by including it in the scope parameter of the authorization request.
Think of ordering a meal at a restaurant with a fixed menu. A Default Client Scope is like the side dishes that automatically arrive with every main course — you don’t have to ask for the bread basket, it just shows up. An Optional Client Scope is like an à la carte add-on, such as extra dessert — it’s available on the menu, but the kitchen only sends it out if you specifically order it. The menu (the realm’s list of Client Scopes) stays the same; what changes is whether an item is bundled automatically or added by request.
Defining a Client Scope and assigning it as Default or Optional to a specific Client are two separate configuration steps. The same Client Scope — say, phone — could be a Default scope for one Client and an Optional scope for a completely different Client, because this assignment happens per-Client, not globally for the scope itself.
Keycloak’s Built-In Client Scopes
Out of the box, a fresh Keycloak realm ships with several ready-made Client Scopes, already sensibly categorized. Commonly included as Default scopes are profile (basic identity fields like name), email, roles (the role claims discussed in earlier guides), web-origins (CORS-related configuration), and acr (authentication context class reference, describing how strongly the user authenticated). Commonly included as Optional scopes are offline_access (long-lived refresh capability), address, phone, and microprofile-jwt (a claim format tailored for certain Java microservice frameworks).
This default categorization reflects a sensible general principle: information nearly every application needs (basic profile, email, roles) is bundled automatically, while more specialized or privacy-sensitive information (a phone number, a physical address, long-lived offline access) is only included when an application specifically asks for it and, depending on configuration, the user explicitly consents to sharing it.
Why This Distinction Exists At All
It would be technically possible for Keycloak to simply include every conceivable piece of user data in every token, all the time. The Default/Optional split exists instead because of three converging concerns: token size (larger tokens cost more bandwidth and parsing time on every single request), data minimization (a well-designed system shares only what’s actually needed, reducing exposure if a token is ever intercepted), and user consent (certain categories of personal data — like a phone number or physical address — are often subject to explicit consent requirements that shouldn’t apply to basic login information).
BArchitecture & Core Components
flowchart TB
Realm["Realm: Client Scopes Catalog"] --> ScopeA["Client Scope: profile"]
Realm --> ScopeB["Client Scope: email"]
Realm --> ScopeC["Client Scope: phone"]
Realm --> ScopeD["Client Scope: offline_access"]
ClientX["Client: Web App"] -->|"Default"| ScopeA
ClientX -->|"Default"| ScopeB
ClientX -->|"Optional"| ScopeC
ClientX -->|"Optional"| ScopeD
ScopeA --> MapperA["Protocol Mappers"]
ScopeC --> MapperC["Protocol Mappers"]
MapperA --> Token["Issued Token"]
MapperC -.->|"only if requested"| Token
Let’s unpack each labeled piece in this architecture.
The Realm-Level Client Scope Catalog
Every Client Scope is defined once, at the realm level, inside a central catalog visible under the realm’s “Client Scopes” section in the Admin Console. This is where the scope’s name, description, and attached Protocol Mappers live — completely independent of any specific Client until it’s assigned to one.
Protocol Mappers Inside a Client Scope
Each Client Scope typically bundles one or more Protocol Mappers — the actual rules that pull specific pieces of data (a user attribute, a role, a group membership) and write them into a token claim with a specific name and format. A single Client Scope like profile might bundle several mappers together: one for given_name, one for family_name, one for preferred_username, and so on.
Per-Client Assignment
Each individual Client has its own configuration listing which Client Scopes are assigned to it, and — critically — whether each assignment is Default or Optional. This is managed in the Client Scopes tab of a specific Client’s settings in the Admin Console, and it’s entirely independent from how that same Client Scope might be assigned to a different Client.
Role Scope Mappings
Beyond claims like email or phone number, Client Scopes can also carry Role Scope Mappings — restricting which of a Client’s available roles are actually eligible to appear in tokens issued under that scope. This gives administrators a second axis of control: not just “which claims appear” but “which roles are even allowed to surface” for a given scope.
People sometimes assume a Client Scope’s category (Default or Optional) is a fixed, global property of the scope itself. It isn’t — the exact same phone Client Scope could be marked Default for an internal HR application (where a phone number is always relevant) while remaining Optional for a public-facing marketing site (where it’s rarely needed and should only be requested when genuinely useful).
The Full Scope Allowed Toggle
Separately from this model entirely, each Client also has a Full Scope Allowed setting. When enabled, it bypasses fine-grained scope-based role filtering altogether, granting the Client access to every realm and client role the user holds, regardless of Client Scope configuration. This is a powerful but coarse setting, discussed further in the Design Patterns chapter, and is generally discouraged for production Clients that don’t genuinely need such broad access.
CHow Default vs. Optional Scope Resolution Works Internally
The scope Parameter in the Authorization Request
When an application initiates a login, it typically includes a scope parameter in its request to Keycloak — a space-separated list of scope names it wants included, such as openid profile email phone. Every OpenID Connect request implicitly includes the special openid scope, which triggers ID Token issuance in the first place.
How Default Scopes Are Resolved
Regardless of what the application explicitly requests in its scope parameter, every Client Scope marked as Default for that Client is automatically included in the resolution process. There’s no need for the requesting application to name them — Keycloak applies them unconditionally as part of that Client’s baseline token contract.
How Optional Scopes Are Resolved
A Client Scope marked as Optional is only included if its exact name appears in the incoming scope parameter of that specific authorization request. If the application never requests phone, the phone Client Scope’s mappers simply never run for that login, and no phone-related claims appear in the resulting token — even though the scope is technically available to that Client if it chose to ask for it.
Think of checking into a hotel that automatically includes breakfast and Wi-Fi with every room (Default scopes) but offers a spa treatment or airport shuttle only if you specifically request them at check-in (Optional scopes). The hotel’s full list of available amenities (the realm’s Client Scope catalog) stays the same for every guest — what changes is which ones actually get delivered to your room, based on what’s automatic versus what you asked for.
Mapper Execution and Claim Assembly
Once Keycloak has determined the final, resolved set of scopes for a given request — combining every Default scope with whichever Optional scopes were explicitly requested — it runs every Protocol Mapper attached to each of those resolved scopes, writing their resulting claims into the appropriate token (ID Token, Access Token, or both, depending on each mapper’s own configuration).
The Resulting scope Claim
Interestingly, the final set of resolved scopes is itself reported back inside the issued token, typically as a scope claim — giving both the client application and any resource server inspecting the token a clear, explicit record of exactly which scopes were actually granted for that specific token, Default and Optional alike.
An application can request an Optional Client Scope by name, but that request is only honored if the scope is actually assigned to that specific Client in the first place (as either Default or Optional). Requesting a scope name that was never assigned to the Client at all is simply ignored — it doesn’t grant unexpected access purely by being mentioned in the request.
DData Flow & the Scope Resolution Lifecycle
flowchart LR
A["1. App builds authorization request with scope parameter"] --> B["2. Keycloak identifies the Client"]
B --> C["3. Every Default Client Scope for this Client is included"]
C --> D["4. Requested scopes checked against Client's assigned Optional scopes"]
D --> E["5. Matching Optional scopes added to resolved set"]
E --> F["6. Consent screen shown if required for Optional scopes"]
F --> G["7. Protocol Mappers for all resolved scopes executed"]
G --> H["8. Token issued with resulting claims + scope claim"]
Request Construction
The client application builds its authorization request, listing whichever scopes it wants to request beyond the implicit baseline.
Client Identification
Keycloak identifies which registered Client is making the request, loading that Client’s specific Default and Optional scope assignments.
Default Scope Inclusion
Every scope marked Default for this Client is automatically added to the resolved set, with no dependency on the request’s scope parameter.
Optional Scope Matching
Each scope named in the request’s scope parameter is checked against the Client’s assigned Optional scopes — only genuine matches are added.
Consent (If Configured)
If the realm or Client requires user consent, and any resolved Optional scopes are marked as requiring it, the user sees a consent screen naming what’s being shared.
Token Assembly
Protocol Mappers for every scope in the final resolved set run, and their resulting claims are written into the appropriate issued tokens.
It’s worth noting this resolution happens fresh on every login and every token refresh — an application that starts requesting an additional Optional scope it hadn’t asked for before will simply begin receiving that scope’s claims on its next fresh authentication, without any change needed on Keycloak’s configuration side, as long as the scope was already assigned to that Client as Optional.
EAdvantages, Disadvantages & Trade-offs
Advantages
- Keeps tokens lean by default, including only what’s genuinely needed for baseline application functionality.
- Lets applications request additional, more specific data only when a particular feature genuinely requires it.
- Supports data-minimization and privacy-by-design principles by making sensitive claims opt-in rather than automatic.
- Enables precise, per-Client tuning — the same scope can behave differently depending on which application it’s attached to.
- Naturally integrates with consent screens, giving users visibility into exactly what optional data an application is requesting.
Disadvantages / Trade-offs
- Requires deliberate configuration — a scope left as Optional when an application actually needs it as Default can cause confusing, hard-to-diagnose missing-claim bugs.
- Adds a layer of indirection that developers integrating a new application must understand and account for in their authorization requests.
- Misconfigured scope assignments can silently under- or over-share data if not reviewed carefully during Client setup.
- Applications must remember to explicitly request every Optional scope they depend on — an easy detail to overlook during development.
A restaurant with a fixed base menu plus optional à la carte add-ons gives diners real flexibility and keeps the base bill lean — but it also means the kitchen staff must clearly understand which items are automatic and which require an explicit order, or a diner might be surprised by a missing side dish they assumed would just show up.
FSecurity Considerations
Data Minimization as a Security Control
Keeping sensitive or rarely needed claims as Optional — rather than Default — reduces the amount of personal data present in every single token, directly shrinking what’s exposed if any individual token is ever intercepted, logged inappropriately, or leaked.
Review Default Scopes for Over-Sharing
It’s worth periodically reviewing exactly which claims are bundled into each Client’s Default scopes — a scope that made sense as Default early in an application’s life might, as the application’s scope of use grows, actually warrant being downgraded to Optional and requested only where genuinely needed.
Enabling Full Scope Allowed on a Client entirely bypasses the deliberate, curated model Default and Optional Client Scopes are designed to provide — granting that Client every realm and client role the user holds, regardless of how carefully scopes were otherwise configured. This setting should be reserved for genuinely trusted, tightly controlled administrative or internal tooling Clients, not applied broadly as a convenience shortcut.
Consent as a Transparency Mechanism
Requiring user consent for Optional scopes that carry more sensitive claims gives users direct visibility into what a specific application is requesting beyond the baseline — an important transparency and trust-building mechanism, particularly for third-party or less-familiar applications connecting to a realm.
Role Scope Mappings as an Additional Filter
Beyond claim-level control, using Role Scope Mappings within a Client Scope to restrict which roles can even appear in that Client’s tokens provides an extra layer of defense — ensuring that even if a role is broadly assigned to a user elsewhere, it doesn’t automatically leak into every application’s token unless that specific Client genuinely needs visibility into it.
The Idea
Keep each Client’s Default scopes limited to genuinely universal baseline claims, pushing anything more specific or sensitive to Optional scopes requested only by the specific application features that need them.
Why It Matters
This mirrors the broader least-privilege principle applied specifically to token contents — every claim included by default is one more piece of data present in every token, whether or not that particular login actually needed it.
GMonitoring, Logging & Metrics
Tracking Token Size Over Time
As Client Scopes are added or reconfigured, it’s worth periodically monitoring the size of issued tokens for high-traffic Clients — a steadily growing token size can indicate scope creep, where claims that are rarely used by the application are nonetheless being included in every single request.
Auditing Scope Requests via Events Logging
Keycloak’s Events Logging system (covered in a companion guide) can be reviewed to understand which scopes applications are actually requesting in practice, helping identify Optional scopes that are consistently requested (and might be better promoted to Default for that Client) versus scopes that are rarely or never used despite being configured.
Consent Screen Analytics
For realms with consent enabled, tracking how often users decline or hesitate on a consent screen listing a specific Optional scope can surface user-experience friction — if a particular scope’s request consistently causes drop-off, it may be worth reconsidering whether that data is genuinely necessary for the flow it supports.
Treat Client Scope configuration the way many teams treat dependency audits in software projects — periodically reviewing which scopes are assigned to which Clients, whether each assignment is still appropriately Default versus Optional, and whether any scopes have quietly become unused legacy configuration worth cleaning up.
Alerting on Unexpected Scope Requests
In higher-security environments, monitoring for authorization requests attempting to request scope names that aren’t assigned to the requesting Client at all can be a useful, low-noise signal — while such requests are simply ignored rather than granted, a pattern of them might indicate misconfigured or misbehaving client integrations worth investigating.
HDesign Patterns & Anti-Patterns
Good Pattern: Default for Baseline, Optional for Feature-Specific Data
Keep Default scopes limited to what nearly every part of an application genuinely needs on every login — identity and basic profile information, typically — while pushing anything tied to a specific feature (like requesting a phone number only for an SMS-notification opt-in flow) into an Optional scope requested only where that feature is actually used.
Good Pattern: Mirror Scope Names to Their OpenID Connect Meaning
Where possible, align custom Client Scope names and behavior with the standard OpenID Connect scope conventions (like profile, email, phone) rather than inventing entirely bespoke naming — this keeps integrations predictable for developers already familiar with the broader OAuth 2.0 and OpenID Connect ecosystem.
Good Pattern: Separate Scopes by Sensitivity, Not Just Feature
Group claims into Client Scopes based partly on how sensitive they are, not purely on which feature uses them — this makes it easier to apply consent requirements or stricter review specifically to the more sensitive scopes without needing to touch less sensitive, more universally needed ones.
What It Looks Like
Marking every available Client Scope as Default for a Client simply to avoid having to configure and remember explicit scope requests in application code.
Why It’s a Problem
It defeats the entire purpose of the Default/Optional distinction, bloats every issued token with claims the application may rarely use, and increases the amount of personal data exposed in every single token regardless of actual need.
What It Looks Like
Enabling Full Scope Allowed on a Client to sidestep configuring Client Scopes carefully, rather than deliberately assigning and tuning Default and Optional scopes for that specific application.
Why It’s a Problem
It grants sweeping, unfiltered access to every realm and client role a user holds, removing the precise, curated control that Client Scopes are specifically designed to provide — a convenience shortcut with outsized security implications.
What It Looks Like
An application depends on an Optional scope’s claims (like offline_access for background sync) but never actually includes that scope name in its authorization requests.
Why It’s a Problem
This produces confusing runtime bugs where a feature silently fails because expected claims or tokens simply never appear, even though the scope was correctly assigned to the Client on Keycloak’s side all along.
IBest Practices & Common Mistakes
Start Minimal, Add Deliberately
Begin with a lean set of Default scopes and add Optional scopes explicitly as specific application features genuinely require them.
Document Scope Requirements Per Application
Keep a clear record of which Optional scopes each application depends on and why, so future developers understand what to request and why it matters.
Test Both With and Without Optional Scopes
Verify application behavior both when an Optional scope is requested and when it isn’t, ensuring graceful handling rather than assuming it will always be present.
Avoid Full Scope Allowed for Ordinary Clients
Reserve this setting for genuinely trusted internal tooling, preferring precise Default and Optional scope configuration for everything else.
Common Mistakes to Avoid
- Assuming a scope is Default when it’s actually Optional: A developer integrating with a new Client may reasonably assume claims they’ve seen in another application’s tokens will “just be there,” without realizing that Client configured the scope differently.
- Not reviewing scope assignments during Client provisioning: New Clients cloned from a template may inherit Default/Optional assignments that don’t actually fit their specific use case.
- Overloading a single Client Scope with unrelated mappers: Bundling unrelated claims into one large scope makes it harder to selectively include only what’s genuinely needed for a specific use case.
- Ignoring consent screen wording: Poorly named or described Optional scopes can confuse users during consent, undermining the very transparency the consent mechanism is meant to provide.
JReal-World & Industry Examples
A Web Application’s Baseline Login
A typical customer-facing web application configures profile, email, and roles as Default scopes — every login automatically includes basic identity and permission information the application needs for virtually every page it renders.
A Mobile App’s Background Sync Feature
A mobile application that needs to sync data periodically, even when the app isn’t actively open, requests the offline_access Optional scope specifically during its initial login, obtaining the long-lived refresh capability that feature requires without burdening every other Client with that same capability by default.
An SMS Notification Opt-In Flow
An application offering optional SMS notifications requests the phone Optional scope only at the specific moment a user opts into that feature, rather than requesting phone number access on every ordinary login — a clean example of scope requests mapping directly to genuine feature need.
A Microservice Using microprofile-jwt
A Java-based microservice expecting claims in a specific format compatible with the MicroProfile JWT specification requests the microprofile-jwt Optional scope, tailoring its token’s claim structure to match what that particular framework expects — without affecting how tokens look for other, unrelated Clients in the same realm.
An Internal Admin Tool Using Full Scope Allowed
A tightly controlled, internal-only administrative tool — accessible to a small, trusted group and protected by additional network restrictions — might reasonably use Full Scope Allowed to simplify its access to a broad range of roles, a deliberate exception rather than a default posture applied broadly.
KFrequently Asked Questions
LSummary & Key Takeaways
Key Takeaways
- Client Scopes are reusable bundles of Protocol Mappers and Role Scope Mappings, defined once at the realm level and assigned per-Client.
- Default Client Scopes are automatically included in every token issued to that Client, with no need for the application to request them explicitly.
- Optional Client Scopes are only included when the application specifically names them in its authorization request’s scope parameter — and only if they’re actually assigned to that Client.
- This distinction supports token size control, data minimization, and meaningful user consent, all at once.
- The same Client Scope can be Default for one Client and Optional for another, since assignment happens per-Client rather than globally.
- Full Scope Allowed is a separate, much coarser setting that bypasses this careful model entirely and should be reserved for genuinely trusted, tightly controlled Clients.
- Well-run deployments keep Default scopes lean, push specialized or sensitive claims to Optional, and periodically audit scope assignments as applications and their needs evolve over time.