Proposal: Token Introspection Enhancement
Context / Problem Statement
Token introspection (RFC 7662) allows resource servers to query an authorization server about the state of a token. In the context of SD-JWT credentials, introspection enables:
- Real-time status checks without downloading and parsing full status lists
- Centralized policy enforcement at the authorization server level
- Enhanced audit trails by centralizing all verification decisions
- Bridge to legacy systems that expect OAuth2-style token validation
The current ecosystem validates tokens locally (offline verification) which is ideal for privacy and performance. However, enterprise deployments often require centralized verification for compliance, audit, and governance reasons.
Goals
- Implement an SD-JWT introspection endpoint (server side)
- Implement an introspection client for resource servers
- Support JWT introspection responses (structured, signed)
- Integrate with existing
SdJwt.Net.StatusList for status resolution
- Support policy-based introspection decisions
Non-Goals
- Replace local verification (introspection is complementary)
- Full OAuth2 authorization server implementation
- Token exchange (RFC 8693)
Proposed Design
Architecture
flowchart LR
subgraph ResourceServer["Resource Server"]
IntrospectClient["Introspection Client<br/>(new)"]
end
subgraph AuthzServer["Authorization / Introspection Server"]
IntrospectEndpoint["Introspection Endpoint<br/>(new)"]
LocalVerifier["SD-JWT Verifier"]
StatusChecker["Status List Checker"]
PolicyEngine["Policy Engine"]
end
IntrospectClient -->|"POST /introspect"| IntrospectEndpoint
IntrospectEndpoint --> LocalVerifier
IntrospectEndpoint --> StatusChecker
IntrospectEndpoint --> PolicyEngine
StatusChecker --> StatusCDN["Status List CDN"]
Component Design
Introspection Endpoint (Server Side)
public class SdJwtIntrospectionEndpoint
{
public Task<IntrospectionResponse> IntrospectAsync(
IntrospectionRequest request);
}
public class IntrospectionRequest
{
public string Token { get; set; }
public string TokenTypeHint { get; set; } // "sd-jwt" or "sd-jwt+vc"
public string Audience { get; set; }
}
public class IntrospectionResponse
{
public bool Active { get; set; }
public string Scope { get; set; }
public string ClientId { get; set; }
public string TokenType { get; set; }
public long? Exp { get; set; }
public long? Iat { get; set; }
public string Iss { get; set; }
public string Sub { get; set; }
public string Aud { get; set; }
// SD-JWT specific
public string Vct { get; set; }
public string Status { get; set; } // "valid", "revoked", "suspended"
public string[] DisclosedClaims { get; set; }
// JWT response (signed)
public string JwtResponse { get; set; }
}
Introspection Client (Resource Server Side)
public class SdJwtIntrospectionClient
{
public SdJwtIntrospectionClient(
string introspectionEndpoint,
HttpClient httpClient,
IntrospectionClientOptions options);
public Task<IntrospectionResponse> IntrospectAsync(string token);
}
public class IntrospectionClientOptions
{
public string ClientId { get; set; }
public string ClientSecret { get; set; }
public bool RequireJwtResponse { get; set; } = true;
public TimeSpan CacheDuration { get; set; } = TimeSpan.FromMinutes(1);
public bool FailClosedOnError { get; set; } = true;
}
Introspection Flow
sequenceDiagram
participant Holder
participant RS as Resource Server
participant IS as Introspection Server
participant SL as Status List CDN
Holder->>RS: Present SD-JWT credential
RS->>IS: POST /introspect (token)
IS->>IS: Verify SD-JWT signature
IS->>SL: Fetch status list
SL-->>IS: Status list
IS->>IS: Check status bit
IS->>IS: Apply policy rules
IS-->>RS: { active: true, status: "valid", vct: "..." }
RS-->>Holder: Access granted
Security Considerations
| Concern |
Mitigation |
| Introspection endpoint DoS |
Rate limiting, client authentication required |
| Token exposure to introspection server |
Server already has trust relationship; TLS in transit |
| Response tampering |
JWT introspection response (signed by server) |
| Privacy (server learns all verification events) |
Trade-off: use only when centralized audit is required |
| Cache poisoning |
Short cache TTL, cryptographic response validation |
Estimated Effort
| Component |
Effort |
SdJwtIntrospectionEndpoint |
4 days |
SdJwtIntrospectionClient |
3 days |
| JWT response signing/validation |
2 days |
| ASP.NET Core integration |
3 days |
| Status list integration |
2 days |
| Tests + documentation |
3 days |
| Total |
17 days |
Alternatives Considered
| Alternative |
Rejected Because |
| Status list only (no introspection) |
Doesn't satisfy enterprise need for centralized audit |
| OCSP protocol |
Different trust model; RFC 7662 is OAuth-native |
| Custom validation API |
Non-standard; RFC 7662 has broad tooling support |