Skip to content

Token introspection verification & integration tests#4180

Draft
stevenvegt wants to merge 1 commit into4144-4-server-side-flowfrom
4144-5-introspection-and-integration
Draft

Token introspection verification & integration tests#4180
stevenvegt wants to merge 1 commit into4144-4-server-side-flowfrom
4144-5-introspection-and-integration

Conversation

@stevenvegt
Copy link
Copy Markdown
Member

Parent PRD

#4144

Implementation Spec

Overview

Verify that multi-scope tokens work correctly with the existing token introspection endpoints, and add end-to-end integration tests covering the full client→server→introspection flow for all three scope policies.

Key files to modify/create

  • auth/api/iam/api_test.go — Introspection tests with multi-scope tokens
  • auth/api/iam/s2s_vptoken_test.go — Integration-style tests
  • Possibly e2e test configs if needed

Design

Token introspection verification

The existing introspection endpoints (IntrospectAccessToken and IntrospectAccessTokenExtended) return the scope field from the stored AccessToken. Since AccessToken.Scope is a string and the OAuth2 spec supports space-delimited scopes, multi-scope tokens should work without code changes.

Verify by:

  1. Creating an AccessToken with a multi-scope Scope field (e.g., "urn:nuts:med-overview patient/Observation.read")
  2. Storing it via the session store
  3. Calling both introspection endpoints
  4. Asserting the scope field in the response contains the full space-delimited string

If any issues are found (e.g., scope parsing in introspection, field validation against reserved names), fix them in this PR.

Integration tests

Add integration-style tests that exercise the full flow:

Test 1: Profile-only, single scope (backwards compatibility)

  • Configure policy with scope_policy: "profile-only" (or absent, testing the default)
  • Client requests token with single scope
  • Server validates VP, issues token
  • Introspect → scope matches

Test 2: Profile-only, multiple scopes (rejection)

  • Client requests token with credential profile scope + extra scopes
  • Client-side flow rejects with invalid_scope

Test 3: Passthrough, multiple scopes

  • Configure policy with scope_policy: "passthrough"
  • Client requests token with credential profile scope + SMART scopes
  • Server issues token with all scopes
  • Introspect → all scopes present

Test 4: Dynamic, PDP approves all

  • Configure policy with scope_policy: "dynamic"
  • Mock AuthZen PDP returns all approved
  • Full flow → token contains all scopes

Test 5: Dynamic, PDP partial denial

  • Mock PDP denies one of the extra scopes
  • Token contains credential profile scope + approved extras only
  • Introspect → only granted scopes

Test 6: Dynamic, PDP denies credential profile scope

  • Mock PDP denies the credential profile scope
  • Token request fails with access_denied

These tests use the existing test infrastructure (newTestClient, mock dependencies) but exercise the full call chain from scope parsing through token creation to introspection.

Testing

This PR is primarily tests. The main deliverable is confidence that:

  • Multi-scope tokens introspect correctly
  • The full flow works end-to-end for each scope policy
  • Backwards compatibility is maintained for single-scope requests

Acceptance Criteria

  • Multi-scope tokens return all granted scopes via introspection
  • Both IntrospectAccessToken and IntrospectAccessTokenExtended handle multi-scope correctly
  • Integration tests cover all three scope policies (profile-only, passthrough, dynamic)
  • Backwards compatibility test passes (single scope, no scope_policy configured)
  • No code changes needed to introspection (or if changes are needed, they are included)

@qltysh
Copy link
Copy Markdown

qltysh bot commented Apr 13, 2026

Qlty

Coverage Impact

⬆️ Merging this pull request will increase total coverage on 4144-4-server-side-flow by 0.01%.

🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

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.

Support mixed OAuth2 scopes with configurable scope policy

1 participant