From 1b30f42e06258db3acaf281c719a7e10204ff47c Mon Sep 17 00:00:00 2001 From: Vault Automation Date: Thu, 12 Mar 2026 03:48:34 -0400 Subject: [PATCH] VAULT-42859: surface authorization_details from inbound JWT into logical.Auth (#12750) (#12919) Co-authored-by: Bianca <48203644+biazmoreira@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- sdk/logical/auth.go | 7 +++++++ vault/request_handling.go | 2 ++ vault/request_handling_test.go | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) diff --git a/sdk/logical/auth.go b/sdk/logical/auth.go index 9ab8fac2d4..c3bfb01a5a 100644 --- a/sdk/logical/auth.go +++ b/sdk/logical/auth.go @@ -124,6 +124,13 @@ type Auth struct { // HTTPRequestPriority contains potential information about the request // priority based on required path capabilities HTTPRequestPriority *uint8 `json:"http_request_priority"` + + // AuthorizationDetails holds fine-grained authorization constraints for the request. + // Each element is a JSON object with at minimum a "type" field. + // It is nil when the token does not carry authorization details. + // It is not included in plugin RPC serialization because it is only needed at request-routing + // time and not during plugin Renew or Revoke operations. + AuthorizationDetails []AuthorizationDetail `json:"authorization_details,omitempty"` } func (a *Auth) GoString() string { diff --git a/vault/request_handling.go b/vault/request_handling.go index e318c7044c..95c085f4e3 100644 --- a/vault/request_handling.go +++ b/vault/request_handling.go @@ -587,6 +587,8 @@ func (c *Core) CheckToken(ctx context.Context, req *logical.Request, unauth bool auth.ActorEntityID = req.Auth.ActorEntityID auth.ActorEntityName = req.Auth.ActorEntityName } + // Copy authorization details from the request to auth so plugins can access them. + auth.AuthorizationDetails = req.EnterpriseTokenAuthorizationDetails twoStepRecover := req.Operation == logical.RecoverOperation && req.RecoverSourcePath != "" && req.RecoverSourcePath != req.Path var alternateRecoverCapability *logical.Operation diff --git a/vault/request_handling_test.go b/vault/request_handling_test.go index 7fe5ebe1d2..34b7271c40 100644 --- a/vault/request_handling_test.go +++ b/vault/request_handling_test.go @@ -641,3 +641,37 @@ func TestRequestHandling_fetchACLTokenEntryAndEntity_NilRequest(t *testing.T) { require.Error(t, err) require.Equal(t, ErrInternalError, err) } + +// TestAuth_AuthorizationDetails_CopiedFromRequest verifies that logical.Auth.AuthorizationDetails +// matches the authorization details already carried on the request. +func TestAuth_AuthorizationDetails_CopiedFromRequest(t *testing.T) { + t.Parallel() + + details := []logical.AuthorizationDetail{ + {"type": "account_information", "scope": "read"}, + {"type": "payment_initiation", "amount": "100"}, + } + + auth := &logical.Auth{} + req := &logical.Request{ + EnterpriseTokenAuthorizationDetails: details, + } + + // Simulate the assignment performed in CheckToken. + auth.AuthorizationDetails = req.EnterpriseTokenAuthorizationDetails + + require.Equal(t, details, auth.AuthorizationDetails, "auth.AuthorizationDetails must equal req.EnterpriseTokenAuthorizationDetails") +} + +// TestAuth_AuthorizationDetails_NilWhenAbsent verifies that auth.AuthorizationDetails is nil +// when the request does not carry authorization details. +func TestAuth_AuthorizationDetails_NilWhenAbsent(t *testing.T) { + t.Parallel() + + auth := &logical.Auth{} + req := &logical.Request{} + + auth.AuthorizationDetails = req.EnterpriseTokenAuthorizationDetails + + require.Nil(t, auth.AuthorizationDetails) +}