Skip to content

Implement the self delegation flow with azp claim inside the act/sub claim#54

Open
Bin4yi wants to merge 4 commits intowso2-extensions:mainfrom
Bin4yi:selfDelegation
Open

Implement the self delegation flow with azp claim inside the act/sub claim#54
Bin4yi wants to merge 4 commits intowso2-extensions:mainfrom
Bin4yi:selfDelegation

Conversation

@Bin4yi
Copy link

@Bin4yi Bin4yi commented Feb 4, 2026

Purpose

Support self-delegation in OAuth2 Token Exchange (token exchange performed by the same actor) and ensure the azp claim is included inside the act claim.

Description

This PR improves token-exchange handling for self-delegation and strengthens validation logic:

  • Self-delegation detection

    • Enhance isSelfDelegationRequest() to verify the token exchange request contains only a subject token, and that the subject token was issued to the same client.
  • Avoid act claim duplication

    • Prevent duplicate act claim creation during token exchange by checking whether an existing act claim is already present.
    • If an act claim exists, preserve it instead of recreating/duplicating it.
  • Improve subject token validation

    • Update validateSubjectTokenForSelfDelegation() to validate mandatory JWT claims.
    • Ensure the issuer is properly validated:
      • First, check whether the issuer appears in the audience (aud) list.
      • If not present, validate whether the iss claim matches the JWT token’s issuer.
  • Add constants

    • Introduce constant variables AZP and CLIENT_ID in Constants.java for consistent claim handling.

Sample (sanitized) token exchange request

POST https://localhost:9443/oauth2/token

  • grant_type: urn:ietf:params:oauth:grant-type:token-exchange
  • subject_token: <JWT_ACCESS_TOKEN>
  • subject_token_type: urn:ietf:params:oauth:token-type:access_token
  • scope: booking:read

Expected (sanitized) response claims

  • Includes act.sub and ensures act.azp is present under act
  • Prevents duplicating act when already available
  • Keeps azp and client binding consistent for self-delegation flows

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Copy link

@wso2-engineering wso2-engineering bot left a comment

Choose a reason for hiding this comment

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

AI Agent Log Improvement Checklist

⚠️ Warning: AI-Generated Review Comments

  • The log-related comments and suggestions in this review were generated by an AI tool to assist with identifying potential improvements. Purpose of reviewing the code for log improvements is to improve the troubleshooting capabilities of our products.
  • Please make sure to manually review and validate all suggestions before applying any changes. Not every code suggestion would make sense or add value to our purpose. Therefore, you have the freedom to decide which of the suggestions are helpful.

✅ Before merging this pull request:

  • Review all AI-generated comments for accuracy and relevance.
  • Complete and verify the table below. We need your feedback to measure the accuracy of these suggestions and the value they add. If you are rejecting a certain code suggestion, please mention the reason briefly in the suggestion for us to capture it.
Comment Accepted (Y/N) Reason
#### Log Improvement Suggestion No: 1
#### Log Improvement Suggestion No: 2

- Refactor isSelfDelegationRequest() to accept pre-parsed JWTClaimsSet
  instead of parsing the subject token internally, and remove throws
  IdentityOAuth2Exception as it no longer performs operations that can throw

- Refactor validateSubjectTokenForSelfDelegation() to accept pre-parsed
  SignedJWT and JWTClaimsSet parameters instead of parsing internally

- Parse subject token once in validateGrant() and pass the result down
  to isSelfDelegationRequest() and validateSubjectTokenForSelfDelegation(),
  eliminating duplicate parsing of the same token
- Add @BeforeMethod to reset shared OAuth2AccessTokenReqDTO request
  parameters before each test, preventing state pollution from tests
  that set actor_token on the shared DTO

- Add ACTOR_SUBJECT_ID constant for delegation test data

- Add testValidateDelegationRequest() (disabled) for the delegation
  positive test case, pending handler fix for isImpersonationRequest()
  to check may_act claim presence

- Add delegationNegativeTestData data provider with 5 negative cases
  covering missing mandatory claims, wrong issuer, and wrong audience
  for both subject and actor tokens

- Add testValidateDelegationRequestNegativeTest() to verify delegation
  validation fails with IdentityOAuth2Exception for all 5 negative cases

- Add getDelegationSubjectToken(), getDelegationActorToken(),
  getDelegationReqParams(), and prepareTokenUtilsForDelegation()
  helper methods following the same pattern as impersonation helpers
AfraHussaindeen pushed a commit to AfraHussaindeen/identity-oauth2-grant-token-exchange that referenced this pull request Mar 2, 2026
AfraHussaindeen pushed a commit to AfraHussaindeen/identity-oauth2-grant-token-exchange that referenced this pull request Mar 2, 2026
@piraveena
Copy link

Can you update the PR description with sample request, and sample JWT access token?

validateMandatoryClaims(claimsSet, subject);

// NOTE: We SKIP impersonator validation for self-delegation
// In self-delegation, there is no may_act claim because the application

Choose a reason for hiding this comment

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

where are we skipping this impersonator validation for self-delegation. Couldn't find the logic for that

Copy link
Author

Choose a reason for hiding this comment

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

as we discussed we consider that there is no maay_act claim in delegation or self delegation. may_act is only in impersonation

* @param tokReqMsgCtx OAuthTokenReqMessageContext
* @return true if the request is a self-delegation request, false otherwise.
*/
private boolean isSelfDelegationRequest(Map<String, String> requestParams, OAuthTokenReqMessageContext tokReqMsgCtx, JWTClaimsSet subjectClaimsSet) {

Choose a reason for hiding this comment

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

formatting issue

Copy link
Author

Choose a reason for hiding this comment

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

solved in pr #55

return false;
}

if (!requestParams.containsKey(TokenExchangeConstants.SUBJECT_TOKEN) ||

Choose a reason for hiding this comment

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

this is already captured in line 366. Redundant line

Copy link
Author

Choose a reason for hiding this comment

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

will solve in pr #55

!requestParams.containsKey(TokenExchangeConstants.SUBJECT_TOKEN_TYPE)) {
return false;
}
if (requestParams.containsKey(TokenExchangeConstants.ACTOR_TOKEN)) {

Choose a reason for hiding this comment

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

Handled in 372. Redundant lines

Copy link
Author

Choose a reason for hiding this comment

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

will handle in pr #55

}

// Check if the client_id claim matches the requesting client
Object clientIdClaim = subjectClaimsSet.getClaim(TokenExchangeConstants.CLIENT_ID);

Choose a reason for hiding this comment

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

azp is an optional claim. Hence we should be able to stick to client_id claim only. Do you have any reasons to fallback to azp and client_id?

Bin4yi added a commit to Bin4yi/identity-oauth2-grant-token-exchange that referenced this pull request Mar 10, 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