Keycloak Full Scope Allowed

By | February 2, 2026

Version: This documentation is based on Keycloak 26.5.2
Source: keycloak/keycloak

This document explains the “Full Scope Allowed” setting in Keycloak, how it affects token content, security implications, and best practices for production environments.

What is Full Scope Allowed?

Full Scope Allowed is a client-level setting that controls which roles appear in access tokens. When enabled, all roles assigned to a user are included in tokens issued for that client. When disabled, only roles that are explicitly mapped through scope mappings are included.

Mermaid Diagram 1 - user

The Security Problem

By default, when Full Scope Allowed is enabled:

  1. Over-privileged tokens: Applications receive more permissions than they need
  2. Principle of Least Privilege violation: Users’ full role set is exposed to every client
  3. Attack surface expansion: Compromised tokens grant access to all user roles
  4. Cross-application data leakage: Client A sees roles meant for Client B

Mermaid Diagram 2

How It Works (Source Code)

ClientModel Interface

From ClientModel.java:197-198:

boolean isFullScopeAllowed();
void setFullScopeAllowed(boolean value);

Token Generation Logic

From TokenManager.java:602-636:

public static Set<rolemodel> getAccess(UserModel user, ClientModel client,
                                        Stream<clientscopemodel> clientScopes) {
    // Get ALL roles the user has (deep resolution including composite roles)
    Set<rolemodel> roleMappings = RoleUtils.getDeepUserRoleMappings(user);

    if (client.isFullScopeAllowed()) {
        // Return ALL user roles - no filtering
        logger.tracef("Using full scope for client %s", client.getClientId());
        return roleMappings;
    } else {
        // 1. Start with client's own roles
        Stream<rolemodel> scopeMappings = client.getRolesStream();

        // 2. Add role mappings from all client scopes
        Stream<rolemodel> clientScopesMappings = clientScopes
            .flatMap(clientScope -&gt; clientScope.getScopeMappingsStream());
        scopeMappings = Stream.concat(scopeMappings, clientScopesMappings);

        // 3. Expand composite roles
        scopeMappings = RoleUtils.expandCompositeRolesStream(scopeMappings);

        // 4. INTERSECTION: Keep only roles that user has AND are in scope
        roleMappings.retainAll(scopeMappings.collect(Collectors.toSet()));

        return roleMappings;  // Filtered roles
    }
}

Role Resolution Flow

Mermaid Diagram 3

Scope Mappings Explained

When Full Scope Allowed is disabled, roles in tokens are determined by scope mappings.

ScopeContainerModel Interface

From ScopeContainerModel.java:

public interface ScopeContainerModel {
    // Get all roles mapped to this scope
    Stream<rolemodel> getScopeMappingsStream();

    // Get only realm-level role mappings
    Stream<rolemodel> getRealmScopeMappingsStream();

    // Add a role to scope mappings
    void addScopeMapping(RoleModel role);

    // Remove a role from scope mappings
    void deleteScopeMapping(RoleModel role);

    // Check if role is in scope
    boolean hasScope(RoleModel role);
}

Where Scope Mappings Come From

Mermaid Diagram 4

Scope Mapping Resolution

From DefaultClientSessionContext.java:303-307:

private Set<rolemodel> loadRoles() {
    UserModel user = clientSession.getUserSession().getUser();
    ClientModel client = clientSession.getClient();
    // This calls TokenManager.getAccess() which applies fullScopeAllowed filtering
    return TokenManager.getAccess(user, client, getClientScopesStream());
}

Default Values by Client Type

From Keycloak’s realm initialization code:

Client Type Default fullScopeAllowed Reason
Admin Console true Needs all admin roles
Admin CLI true Needs all admin roles
Realm Management false Bearer-only, restricted access
Account Management false Limited to account operations
Account Console false Limited to account operations
Broker Service false Limited to broker operations
User-created clients false Security best practice

Important: New clients created through Admin Console or API have fullScopeAllowed = false by default.

Token Comparison

With Full Scope Allowed = TRUE

{
"sub": "user-123",
"realm_access": {
"roles": [
"admin",
"user",
"offline_access",
"uma_authorization"
]
},
"resource_access": {
"billing-service": {
"roles": ["view-invoices", "create-invoices", "delete-invoices"]
},
"hr-system": {
"roles": ["view-employees", "manage-employees"]
},
"reporting-service": {
"roles": ["view-reports", "export-reports", "admin"]
},
"account": {
"roles": ["manage-account", "view-profile"]
}
}
}

With Full Scope Allowed = FALSE (Properly Configured)

{
"sub": "user-123",
"realm_access": {
"roles": [
"user"
]
},
"resource_access": {
"billing-service": {
"roles": ["view-invoices"]
}
}
}

Configuration Guide

Step 1: Disable Full Scope Allowed

In Admin Console: Clients ? Select client ? Settings ? Full scope allowed = OFF

Or via API:

curl -X PUT \
  "https://keycloak.example.com/admin/realms/myrealm/clients/{client-id}" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"fullScopeAllowed": false}'

Step 2: Configure Scope Mappings

Option A: Client Scope Role Mappings

  1. Clients ? Select client ? Client scopes tab
  2. Select a default or optional client scope
  3. Scope tab ? Assign role
  4. Select roles this client should have access to

Mermaid Diagram 5

Option B: Direct Client Scope Mappings

  1. Clients ? Select client ? Client scopes tab
  2. Click on {client-id}-dedicated scope
  3. Scope tab ? Assign role
  4. Select roles

Step 3: Verify Token Content

Use the Token Exchange or Evaluate tab to verify tokens only contain expected roles.

Best Practices

1. Always Disable Full Scope Allowed in Production

Mermaid Diagram 6

2. Principle of Least Privilege

Only grant roles that the client actually needs:

Client Needed Roles Unnecessary Roles
Blog App user admin, billing:*, hr:*
Billing Portal billing:view, billing:create admin, hr:*, reporting:*
HR System hr:view, hr:manage admin, billing:*

3. Use Client Scopes for Role Groups

Create reusable client scopes for common role combinations:

Mermaid Diagram 7

4. Audit Token Content Regularly

Periodically review what roles are being included in tokens:

# Get a token and decode it
TOKEN=$(curl -s -X POST \
  "https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token" \
  -d "client_id=my-client" \
  -d "client_secret=secret" \
  -d "username=testuser" \
  -d "password=password" \
  -d "grant_type=password" | jq -r '.access_token')

# Decode and inspect
echo $TOKEN | cut -d'.' -f2 | base64 -d | jq '.realm_access, .resource_access'

5. Use Dedicated Client Scopes

Don’t rely on default scopes for sensitive role mappings:

? Create "billing-api-access" scope with specific roles
? Add roles to the built-in "roles" scope

6. Document Role Requirements

For each client, document:

  • Which roles are required
  • Why each role is needed
  • Which client scopes provide them

Security Implications

Risk: Over-Privileged Tokens

Scenario Risk Mitigation
Token theft Attacker gains all user permissions Disable full scope, limit roles
XSS attack Malicious script accesses all APIs Reduce token scope
Compromised client All user roles exposed Scope to client’s needs only
Token forwarding Downstream service gets excessive access Use audience restrictions + scope limits

Risk: Cross-Tenant Data Access

In multi-tenant setups with shared users:

Mermaid Diagram 8

FAPI Compliance

FAPI (Financial-grade API) profiles require fullScopeAllowed = false:

From keycloak-default-client-profiles.json:

{
"name": "fapi-1-baseline",
"executors": [
{
"executor": "full-scope-disabled",
"configuration": {
"auto-configure": true
}
}
]
}

The full-scope-disabled executor:

  • Automatically sets fullScopeAllowed = false on client registration/update
  • Prevents enabling full scope for FAPI-compliant clients

Database Schema

From ClientEntity.java:

-- Client table stores fullScopeAllowed flag
CREATE TABLE CLIENT (
    ID                  VARCHAR(36) PRIMARY KEY,
    CLIENT_ID           VARCHAR(255),
    REALM_ID            VARCHAR(36),
    FULL_SCOPE_ALLOWED  BOOLEAN DEFAULT FALSE,
    -- ... other columns
);

-- Scope mappings stored in separate table
CREATE TABLE SCOPE_MAPPING (
    CLIENT_ID   VARCHAR(36) NOT NULL,
    ROLE_ID     VARCHAR(36) NOT NULL,
    PRIMARY KEY (CLIENT_ID, ROLE_ID),
    FOREIGN KEY (CLIENT_ID) REFERENCES CLIENT(ID),
    FOREIGN KEY (ROLE_ID) REFERENCES KEYCLOAK_ROLE(ID)
);

-- Client scope role mappings
CREATE TABLE CLIENT_SCOPE_ROLE_MAPPING (
    SCOPE_ID    VARCHAR(36) NOT NULL,
    ROLE_ID     VARCHAR(36) NOT NULL,
    PRIMARY KEY (SCOPE_ID, ROLE_ID),
    FOREIGN KEY (SCOPE_ID) REFERENCES CLIENT_SCOPE(ID),
    FOREIGN KEY (ROLE_ID) REFERENCES KEYCLOAK_ROLE(ID)
);

Checklist for Production

  • [ ] Disable fullScopeAllowed for all production clients
  • [ ] Create dedicated client scopes for role groups
  • [ ] Map only required roles to each client
  • [ ] Use optional scopes for elevated permissions
  • [ ] Document role requirements per client
  • [ ] Enable FAPI profile for financial applications
  • [ ] Audit tokens regularly for scope creep
  • [ ] Review scope mappings during security audits
Component File
ClientModel Interface ClientModel.java
TokenManager TokenManager.java
ScopeContainerModel ScopeContainerModel.java
ClientSessionContext ClientSessionContext.java
DefaultClientSessionContext DefaultClientSessionContext.java
RoleResolveUtil RoleResolveUtil.java
FullScopeDisabledExecutor FullScopeDisabledExecutor.java
ClientEntity ClientEntity.java

References

Leave a Reply