|
8 | 8 | <description>Keycloak Blog</description> |
9 | 9 | <language>en-us</language> |
10 | 10 | <category>Keycloak/SSO/Identity and Access Management</category> |
| 11 | + <item> |
| 12 | + <title>JWT Authorization Grant and Identity Chaining in Keycloak 26.5</title> |
| 13 | + <link>https://www.keycloak.org/2026/01/jwt-authorization-grant</link> |
| 14 | + <description><div class="paragraph"> |
| 15 | +<p>Modern applications and AI agents increasingly operate across distributed trust domains, where each domain is protected by its own OAuth 2.0 Authorization Server. A single request may also traverse multiple resource servers to complete a task.</p> |
| 16 | +</div> |
| 17 | +<div class="paragraph"> |
| 18 | +<p>This raises an important challenge: every protected resource must understand <strong>who initiated the request</strong>, which <strong>authorization</strong> was granted, and optionally which other resources were accessed before making an authorization decision. Preserving this information across domains is critical.</p> |
| 19 | +</div> |
| 20 | +<div class="paragraph"> |
| 21 | +<p><strong>Keycloak 26.5</strong> introduces <strong>preview</strong> support for the new feature <strong>JWT Authorization Grant</strong>, implementing <a href="https://datatracker.ietf.org/doc/html/rfc7523">RFC 7523</a>. This feature allows a client to present a signed JWT from an external issuer and obtain a Keycloak access token, providing a <strong>standard and secure way to authorize requests based on external assertions</strong>.</p> |
| 22 | +</div> |
| 23 | +<div class="paragraph"> |
| 24 | +<p>However, exchanging a token alone does not fully solve the problem of propagating identity and authorization context across multiple trust domains.</p> |
| 25 | +</div> |
| 26 | +<div class="paragraph"> |
| 27 | +<p>The IETF draft <strong>OAuth Identity and Authorization Chaining Across Domains</strong> defines a standardized flow that combines <strong>JWT Authorization Grant (RFC 7523)</strong> with <strong>OAuth 2.0 Token Exchange (RFC 8693)</strong>, <strong>which Keycloak already supports</strong>, to preserve the original user’s identity, claims, and authorization throughout the chain.</p> |
| 28 | +</div> |
| 29 | +<div class="sect1"> |
| 30 | +<h2 id="_jwt_authorization_grant"><a class="anchor" href="#_jwt_authorization_grant"></a>JWT Authorization Grant</h2> |
| 31 | +<div class="sectionbody"> |
| 32 | +<div class="paragraph"> |
| 33 | +<p>The JWT Authorization Grant feature allows a client to present a signed JWT assertion to the token endpoint and obtain an access token without an interactive authorization step. To initiate this flow, the client sends a request to the <strong>token endpoint</strong> with the <code>grant_type</code> set to <strong><code>urn:ietf:params:oauth:grant-type:jwt-bearer</code></strong> and the external token passed in the <strong><code>assertion</code></strong> parameter.</p> |
| 34 | +</div> |
| 35 | +<div class="paragraph"> |
| 36 | +<p>It provides a standard and secure alternative to the preview feature External-to-Internal Token Exchange V1 which will be deprecated.</p> |
| 37 | +</div> |
| 38 | +<div class="paragraph"> |
| 39 | +<p>Trust relationships in Keycloak are defined through Identity Providers. The JWT Authorization Grant can be enabled and configured in a dedicated section of the existing OpenID Connect v1.0 Identity Provider, or via a new dedicated JWT Authorization Grant Identity Provider.</p> |
| 40 | +</div> |
| 41 | +<div class="paragraph"> |
| 42 | +<p>A confidential client can request a JWT Authorization Grant by enabling the dedicated option in the client settings and selecting the allowed identity providers.</p> |
| 43 | +</div> |
| 44 | +<div class="admonitionblock note"> |
| 45 | +<table> |
| 46 | +<tr> |
| 47 | +<td class="icon"> |
| 48 | +<i class="fa icon-note" title="Note"></i> |
| 49 | +</td> |
| 50 | +<td class="content"> |
| 51 | +The JWT Authorization Grant is a preview feature. Full configuration details are available in a dedicated guide: |
| 52 | +<a href="https://www.keycloak.org/securing-apps/jwt-authorization-grant">JWT Authorization Grant</a>. |
| 53 | +</td> |
| 54 | +</tr> |
| 55 | +</table> |
| 56 | +</div> |
| 57 | +</div> |
| 58 | +</div> |
| 59 | +<div class="sect1"> |
| 60 | +<h2 id="_oauth_identity_and_authorization_chaining_across_domains"><a class="anchor" href="#_oauth_identity_and_authorization_chaining_across_domains"></a>OAuth Identity and Authorization Chaining Across Domains</h2> |
| 61 | +<div class="sectionbody"> |
| 62 | +<div class="paragraph"> |
| 63 | +<p>Although the JWT Authorization Grant allows a client to obtain a Keycloak access token based on an external JWT, it does not by itself solve the broader problem of propagating identity and authorization context across multiple trust domains.</p> |
| 64 | +</div> |
| 65 | +<div class="paragraph"> |
| 66 | +<p>To propagate identity across multiple trust domains, the <a href="https://www.keycloak.org/securing-apps/jwt-authorization-grant"><strong>JWT Authorization Grant</strong></a> (RFC 7523) is combined with <a href="https://www.keycloak.org/securing-apps/token-exchange#_standard-token-exchange"><strong>Standard Token Exchange</strong></a> (RFC 8693), already supported by Keycloak.</p> |
| 67 | +</div> |
| 68 | +<div class="paragraph"> |
| 69 | +<p>This integration implements the flow defined in the IETF draft <a href="https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-chaining"><strong>OAuth Identity and Authorization Chaining Across Domains</strong></a>.</p> |
| 70 | +</div> |
| 71 | +<div class="paragraph"> |
| 72 | +<p>A typical scenario involves <strong>Domain A</strong> (an external IdP or Keycloak realm) and <strong>Domain B</strong> (an internal Keycloak realm). The goal is to allow a client in Domain A to access resources in Domain B while preserving the original user&#8217;s identity.</p> |
| 73 | +</div> |
| 74 | +<div class="sect2"> |
| 75 | +<h3 id="_step_1_token_exchange_in_domain_a"><a class="anchor" href="#_step_1_token_exchange_in_domain_a"></a>Step 1: Token Exchange in Domain A</h3> |
| 76 | +<div class="paragraph"> |
| 77 | +<p>In this first step, the client requests a token for Domain B using a Token Exchange request.</p> |
| 78 | +</div> |
| 79 | +<div class="paragraph"> |
| 80 | +<p>The client in Domain A must be configured to allow the target audience, typically by assigning a <strong>Client Scope</strong> with an <strong>Audience Mapper</strong> if you are using Keycloak for Domain A. The <code>audience</code> parameter in the request is then used to <strong>restrict</strong> the resulting token to that specific target, ensuring it contains the correct <code>aud</code> claim for Domain B.</p> |
| 81 | +</div> |
| 82 | +<div class="listingblock"> |
| 83 | +<div class="content"> |
| 84 | +<pre class="highlight"><code class="language-bash" data-lang="bash"># Request to Domain A |
| 85 | +POST /realms/domain-a/protocol/openid-connect/token |
| 86 | +Content-Type: application/x-www-form-urlencoded |
| 87 | + |
| 88 | +grant_type=urn:ietf:params:oauth:grant-type:token-exchange |
| 89 | +&amp;subject_token=$ORIGINAL_ACCESS_TOKEN |
| 90 | +&amp;audience=http://localhost:8080/realms/domain-b</code></pre> |
| 91 | +</div> |
| 92 | +</div> |
| 93 | +<div class="paragraph"> |
| 94 | +<p>Domain A issues a new JWT access token, which acts as the assertion for Domain B.</p> |
| 95 | +</div> |
| 96 | +</div> |
| 97 | +<div class="sect2"> |
| 98 | +<h3 id="_step_2_jwt_authorization_grant_in_domain_b"><a class="anchor" href="#_step_2_jwt_authorization_grant_in_domain_b"></a>Step 2: JWT Authorization Grant in Domain B</h3> |
| 99 | +<div class="paragraph"> |
| 100 | +<p>The client uses this token to authenticate with Domain B using the <strong>JWT Authorization Grant</strong>.</p> |
| 101 | +</div> |
| 102 | +<div class="listingblock"> |
| 103 | +<div class="content"> |
| 104 | +<pre class="highlight"><code class="language-bash" data-lang="bash"># Request to Domain B |
| 105 | +POST /realms/domain-b/protocol/openid-connect/token |
| 106 | +Content-Type: application/x-www-form-urlencoded |
| 107 | + |
| 108 | +grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer |
| 109 | +&amp;assertion=$TOKEN_FROM_STEP_1</code></pre> |
| 110 | +</div> |
| 111 | +</div> |
| 112 | +<div class="paragraph"> |
| 113 | +<p>Domain B validates the token and issues a local access token. Identity and authorization context are now securely propagated from Domain A to Domain B.</p> |
| 114 | +</div> |
| 115 | +<div class="admonitionblock note"> |
| 116 | +<table> |
| 117 | +<tr> |
| 118 | +<td class="icon"> |
| 119 | +<i class="fa icon-note" title="Note"></i> |
| 120 | +</td> |
| 121 | +<td class="content"> |
| 122 | +This flow can be fully configured with Keycloak. For more configuration details check the dedicated guide: |
| 123 | +<a href="https://www.keycloak.org/nightly/securing-apps/oauth-identity-authorization-chaining-across-domains">OAuth Identity and Authorization Chaining Across Domains</a>. |
| 124 | +</td> |
| 125 | +</tr> |
| 126 | +</table> |
| 127 | +</div> |
| 128 | +</div> |
| 129 | +</div> |
| 130 | +</div> |
| 131 | +<div class="sect1"> |
| 132 | +<h2 id="_why_this_new_feature"><a class="anchor" href="#_why_this_new_feature"></a>Why this new feature?</h2> |
| 133 | +<div class="sectionbody"> |
| 134 | +<div class="paragraph"> |
| 135 | +<p>The JWT Authorization Grant solves an important problem in cross-domain OAuth flows. It lets an Authorization Server issue tokens based on a <strong>signed JWT assertion</strong>, making authorization decisions explicit and verifiable. Combined with Identity Chaining, it allows each domain to check and extend authorization context in a standards-based way.</p> |
| 136 | +</div> |
| 137 | +<div class="paragraph"> |
| 138 | +<p>JWT Authorization Grant brings several advantages:</p> |
| 139 | +</div> |
| 140 | +<div class="ulist"> |
| 141 | +<ul> |
| 142 | +<li> |
| 143 | +<p><strong>Preserves user identity</strong>. Cross-domain access often relies on generic service accounts to call APIs. With a signed JWT assertion, a service can request tokens on behalf of a user, keeping identity and intent clear when moving across domains.</p> |
| 144 | +</li> |
| 145 | +<li> |
| 146 | +<p><strong>Standards-based cross-domain support</strong>. The JWT Authorization Grant with the support of the RFC 7523 is part of ongoing OAuth work on cross-domain identity and authorization chaining, including |
| 147 | +<a href="https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-chaining">OAuth Identity and Authorization Chaining Across Domains</a> and |
| 148 | +<a href="https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-assertion-authz-grant">Identity Assertion Authorization Grant</a>. |
| 149 | +This allows workflows that are traceable, constrained, and aligned with least-privilege principles, ideal for distributed systems and AI agents.</p> |
| 150 | +</li> |
| 151 | +</ul> |
| 152 | +</div> |
| 153 | +</div> |
| 154 | +</div> |
| 155 | +<div class="sect1"> |
| 156 | +<h2 id="_next_steps"><a class="anchor" href="#_next_steps"></a>Next Steps</h2> |
| 157 | +<div class="sectionbody"> |
| 158 | +<div class="ulist"> |
| 159 | +<ul> |
| 160 | +<li> |
| 161 | +<p>Promote JWT Authorization Grant from preview to a fully supported feature in the next Keycloak release</p> |
| 162 | +</li> |
| 163 | +<li> |
| 164 | +<p>Deprecate Token Exchange version 1</p> |
| 165 | +</li> |
| 166 | +<li> |
| 167 | +<p>Enable JWT Authorization Grant for social Identity Providers (e.g., Google)</p> |
| 168 | +</li> |
| 169 | +<li> |
| 170 | +<p>Monitor and follow the evolution of the Identity Chaining draft to ensure full compliance</p> |
| 171 | +</li> |
| 172 | +</ul> |
| 173 | +</div> |
| 174 | +</div> |
| 175 | +</div> |
| 176 | +<div class="sect1"> |
| 177 | +<h2 id="_try_it_out"><a class="anchor" href="#_try_it_out"></a>Try It Out</h2> |
| 178 | +<div class="sectionbody"> |
| 179 | +<div class="paragraph"> |
| 180 | +<p>As the <strong>JWT Authorization Grant</strong> is currently in <strong>preview</strong>, your feedback is helpful to help to refine the feature before it reaches full support.</p> |
| 181 | +</div> |
| 182 | +<div class="paragraph"> |
| 183 | +<p>We encourage you to test this new feature and share your experience. Feedback and contributions from the community are always welcome.</p> |
| 184 | +</div> |
| 185 | +</div> |
| 186 | +</div></description> |
| 187 | + <guid>https://www.keycloak.org/2026/01/jwt-authorization-grant</guid> |
| 188 | + <pubDate>Fri, 23 Jan 2026 00:00:00 GMT</pubDate> |
| 189 | + |
| 190 | + <author>Giuseppe Graziano</author> |
| 191 | + </item> |
11 | 192 | <item> |
12 | 193 | <title>Keycloak 26.5.2 released</title> |
13 | 194 | <link>https://www.keycloak.org/2026/01/keycloak-2652-released</link> |
|
0 commit comments