Skip to content

feat: validate CTE actor token pairing and surface act claim for delegation/impersonation#122

Merged
kishore7snehil merged 6 commits into
mainfrom
feat/cte-delegation
Jun 25, 2026
Merged

feat: validate CTE actor token pairing and surface act claim for delegation/impersonation#122
kishore7snehil merged 6 commits into
mainfrom
feat/cte-delegation

Conversation

@kishore7snehil

@kishore7snehil kishore7snehil commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

📋 Changes

This PR completes Custom Token Exchange (CTE) Delegation/Impersonation support (RFC 8693) in auth0-server-python. CTE input validation moves into the exchange methods so callers get typed CustomTokenExchangeErrors with specific codes, the actor_token/actor_token_type pairing is enforced in both directions, and the act claim from a delegation/impersonation exchange is surfaced to the developer.

✨ Features

  • Actor-token pairing (symmetric): custom_token_exchange and login_with_custom_token_exchange now reject actor_token without actor_token_type (MISSING_ACTOR_TOKEN_TYPE) and actor_token_type without actor_token (MISSING_ACTOR_TOKEN), matching how Auth0 enforces the pair.
  • act claim surfacing: When an exchange includes an actor token, the SDK verifies the returned ID token and exposes the RFC 8693 §4.1 act claim on TokenExchangeResponse.act (stateless) and on the persisted session user, readable back via get_user() (session-creating).
  • Typed validation: Empty/whitespace and Bearer -prefixed tokens now raise CustomTokenExchangeError(INVALID_TOKEN_FORMAT).

🔧 API Changes

  • New error code CustomTokenExchangeErrorCode.MISSING_ACTOR_TOKEN
  • TokenExchangeResponse.act: Optional[dict[str, Any]]
  • CTE input validation now runs inside custom_token_exchange / login_with_custom_token_exchange and raises CustomTokenExchangeError with a specific code (INVALID_TOKEN_FORMAT, MISSING_ACTOR_TOKEN_TYPE, MISSING_ACTOR_TOKEN)

⚠️ Minor breaking change — exception type on invalid input: CTE input validation moved out of the Pydantic models and into the exchange methods. Previously, invalid input (e.g. an empty token) raised a Pydantic ValidationError at the point you constructed CustomTokenExchangeOptions. It now raises a CustomTokenExchangeError with a specific code at call time instead. If you were catching ValidationError for this, switch to catching CustomTokenExchangeError.

📖 Documentation

  • Updated examples/CustomTokenExchange.md with act read-back (stateless and session), the refresh-token suppression note, and the MISSING_ACTOR_TOKEN error code

🧪 Testing

  • This change adds test coverage
  • This change has been tested on the latest version of the platform/language

Contributor Checklist

@kishore7snehil kishore7snehil requested a review from a team as a code owner June 20, 2026 09:13
@kishore7snehil kishore7snehil changed the title feat: validate CTE actor token pairing and surface act claim for delegation feat: validate CTE actor token pairing and surface act claim for delegation/impersonation Jun 20, 2026
The act-claim enrichment in custom_token_exchange ran _verify_and_decode_jwt
with no error handling, so a present-but-undecodable id_token turned an
already-issued exchange into a generic TOKEN_EXCHANGE_FAILED. It also skipped
the normalized issuer check the login path applies before trusting claims.

Wrap the enrichment so any decode/verify failure leaves act=None instead of
failing the exchange, and apply the issuer check before reading the claim.
Rewrite the opaque-token test (it never exercised the decode path) and add
coverage for the undecodable-id_token and issuer-mismatch cases.
Comment thread src/auth0_server_python/auth_server/server_client.py
Comment thread src/auth0_server_python/auth_server/server_client.py
Comment thread src/auth0_server_python/auth_server/server_client.py
Comment thread src/auth0_server_python/auth_server/server_client.py
Comment thread src/auth0_server_python/auth_server/server_client.py
Comment thread src/auth0_server_python/auth_types/__init__.py
Comment thread src/auth0_server_python/tests/test_server_client.py
Comment thread src/auth0_server_python/tests/test_server_client.py Outdated
…urcing

Add local empty/whitespace guards for subject_token_type and actor_token so
they fail with a clear INVALID_TOKEN_FORMAT instead of a generic round-trip
error from the token endpoint, matching the existing subject_token check.
Add tests for both cases.

Document that response.act is read from the id_token and that Auth0 writes
the same act onto the access token (verified against the platform token
dialects), noting the access token may be opaque. Add a comment on the login
path noting act reaches the session user via UserClaims. Rename the refresh
test to reflect that it pins the state-merge behavior the refresh path uses.
Comment thread src/auth0_server_python/auth_server/server_client.py
Comment thread src/auth0_server_python/auth_server/server_client.py
rmad17
rmad17 previously approved these changes Jun 25, 2026

@rmad17 rmad17 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Refresh the lock for the open dependabot pip bumps in one go: idna 3.13 to
3.18, pyjwt 2.12.1 to 2.13.0, pydantic 2.13.3 to 2.13.4 (pydantic-core
2.46.4), and ruff 0.15.11 to 0.15.19. All within the existing pyproject
constraints; full suite passes. Supersedes #110, #113, #118, #119.
Update GitHub Actions pins across the workflows: actions/checkout v6 to v7
(publish, test, codeql) and actions/cache v5 to v6 (test). Supersedes #121,
#123.
@kishore7snehil kishore7snehil merged commit 574b1a6 into main Jun 25, 2026
9 checks passed
@kishore7snehil kishore7snehil deleted the feat/cte-delegation branch June 25, 2026 08:49
@kishore7snehil kishore7snehil mentioned this pull request Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants