Skip to content

Pin access token claim serialization - #517

Merged
thomasluizon merged 2 commits into
mainfrom
chore/ticket-494-jwt-claim-pin
Sep 10, 2026
Merged

Pin access token claim serialization#517
thomasluizon merged 2 commits into
mainfrom
chore/ticket-494-jwt-claim-pin

Conversation

@thomasluizon

@thomasluizon thomasluizon commented Sep 10, 2026

Copy link
Copy Markdown
Owner

Closes #494

Summary

  • Decode payload segment 1 from a token produced by the real JwtTokenService.
  • Pin the complete raw property set, literal claim keys, deterministic values, and every JSON value kind.
  • Name the mobile getUserFromPayload reader and Android OrbitWidgetModule.accountId reader in the contract comment.

Contract evidence

The raw producer shape was derived by generating a token through the real JwtTokenService and decoding payload segment 1, as recorded in #494. The added test repeats that derivation from the real producer on every run.

Assumptions

  • Co-located the contract in JwtTokenServiceTests.cs rather than creating a separate test class because serialization belongs to the existing service boundary.

Test evidence

  • Existing test with defect present: dotnet test tests/Orbit.Infrastructure.Tests --no-restore --filter FullyQualifiedName~JwtTokenServiceTests passed 7 of 7 tests with a temporary extra raw role claim, showing the old tests did not pin the raw property set.
  • Strengthened test with defect present: the same command failed GenerateToken_RawPayloadPreservesClientContract because role was an extraneous payload property.
  • Restored producer: the same command passed 8 of 8 tests.
  • dotnet build Orbit.slnx completed with 0 errors.
  • dotnet test passed 6,163 tests with 0 failures.

@thomasluizon

Copy link
Copy Markdown
Owner Author

Approach: extend tests/Orbit.Infrastructure.Tests/Services/JwtTokenServiceTests.cs with a contract test that splits the token, base64url decodes payload segment 1, parses it with JsonDocument, and asserts the exact property set plus each value and JsonValueKind. Keep this beside the existing JwtTokenService tests because serialization is the service contract. Do not change JwtTokenService because the measured current payload is the required behavior. Reject JwtSecurityTokenHandler based assertions because inbound claim mapping hides raw key changes, and reject a separate fixture because deriving the payload from the real producer is the evidence this ticket requires. The contract comment will name apps/mobile/stores/auth-store.ts getUserFromPayload and OrbitWidgetModule.accountId as the consumers.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Important

This head has no changed files, so the promised access token serialization contract is not present and the PR is not ready to merge.

Reviewed changes I reviewed the only commit currently on chore/ticket-494-jwt-claim-pin against main.

  • Setup commit: 9723455 is empty; no service or test changes are available for review.

⚠️ The raw JWT payload remains unpinned

The existing tests check selected claims after parsing a token, but they do not assert the complete raw payload property set, JSON value kinds, or scalar representations consumed by the mobile app. Because this PR adds no contract assertion, merging it would leave the compatibility risk described in the title unresolved.

Technical details
# Add the serialization contract before merge

## Affected sites
- `tests/Orbit.Infrastructure.Tests/Services/JwtTokenServiceTests.cs:30`: the current tests do not pin the complete raw payload emitted by `JwtTokenService`.
- `apps/mobile/stores/auth-store.ts:65` in `orbit-ui-mobile`: installed clients decode the token payload directly and read serialized identity and expiry claims.

## Required outcome
- Add a test over a token generated by the real `JwtTokenService` that base64url decodes the payload and pins the expected property names, values, and JSON kinds.
- Preserve the raw claim keys and representations accepted by shipped mobile clients.

Pullfrog  | Fix it ➔View workflow run | Using GPT Sol𝕏

@thomasluizon

Copy link
Copy Markdown
Owner Author

@pullfrog review

@sonarqubecloud

Copy link
Copy Markdown

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes I reviewed the raw JWT payload contract added since the prior Pullfrog review.

  • Serialization contract: Added a test over the real JwtTokenService that base64url decodes the payload and pins the complete property set, literal claim keys, configured and identity values, and every JSON value kind consumed by clients.

Pullfrog  | View workflow run | Using GPT Sol𝕏

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes I reviewed the full two-commit PR, including the claim contract added after the earlier empty setup commit.

  • Raw payload extraction: The test base64url-decodes payload segment 1 from a token generated by the real JwtTokenService and parses the serialized JSON directly.
  • Serialized claim contract: The assertion pins the complete property set, literal identity claim keys, configured values, JSON value kinds, GUID jti, and integer timestamp representations.
  • Consumer context: The contract is colocated with existing service tests and identifies the mobile authentication and Android widget compatibility surfaces it protects.

Pullfrog  | View workflow run | Using GPT Sol𝕏

@thomasluizon
thomasluizon merged commit e1a32c5 into main Sep 10, 2026
26 checks passed
@thomasluizon
thomasluizon deleted the chore/ticket-494-jwt-claim-pin branch September 10, 2026 12:05
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.

1 participant