Identity Assertion JWT Authorization Grant (ID-JAG) Support
- Dominant language
- Python
- Stars
- 44.8k
- Forks
- 4.9k
- Avg merge
- 21h 10m
- Merged PRs (30d)
- 635
Description
## Summary
Implement the [Identity Assertion JWT Authorization Grant (ID-JAG)]() specification to enable enterprise SSO-to-API access.
This allows tools like Cursor to authenticate against Sentry API using existing enterprise IdP tokens (Okta, Azure AD, etc.), enabling seamless developer tooling access via SSO.
**Related**: [RTC-1286](https://linear.app/getsentry/issue/RTC-1286/oauth-21-plan-and-tracking) (OAuth 2.1 compliance) - this is a side quest extending that work
### Use Case: Cursor + Okta + Sentry
**Scenario**: Developer at Acme Corp uses Cursor to access Sentry via enterprise SSO.
```
┌──────────┐ ┌──────────────┐ ┌──────────────┐ ┌─────────┐
│ Cursor │ │ Acme Okta │ │ Sentry │ │ Sentry │
└────┬─────┘ └──────┬───────┘ └──────┬───────┘ └────┬────┘
│ 1. OIDC login │ │ │
│─────────────────►│ │ │
│ ◄── ID Token ───│ │ │
│ │ │ │
│ 2. Token Exchange (audience=sentry.io)│ │
│─────────────────►│ │ │
│ ◄── ID-JAG ─────│ │ │
│ │ │ │
│ 3. JWT Bearer Grant (assertion=ID-JAG)│ │
│──────────────────────────────────────►│ │
│ ◄── Access Token (org-scoped) ───────│ │
│ │ │ │
│ 4. API calls ────────────────────────────────────────────►
```
**Flow**:
1. Developer clicks "Login with SSO" in Cursor → authenticates with Okta
2. Cursor exchanges ID token for ID-JAG targeting Sentry
3. Cursor presents ID-JAG to Sentry's token endpoint
4. Sentry validates, maps user via SSO identity, issues org-scoped token
5. Cursor accesses Sentry API
### Client Registration Options
How is Cursor registered with Sentry?
The `client_id` in ID-JAG must match client authentication. Options:
**A. Pre-Registered Apps** (recommended for MVP)
* Sentry pre-creates entries for known tools (Cursor, VS Code, etc.)
* Enterprises enable in org settings
**B. Dynamic Registration (RFC 7591)**
* Tools self-register on first use
* More flexible, security concerns
**C. IdP-Managed Trust**
* No Sentry registration, trust IdP's client_id directly
* IdP controls everything
**D. Hybrid Mapping**
* Sentry client_id maps to IdP client_ids per issuer
## Requirements Checklist
### P0 - Critical
- [ ] **JWT Bearer Grant** (`urn:ietf:params:oauth:grant-type:jwt-bearer`)
- [ ] Accept `assertion` parameter at `/oauth/token`
- [ ] Validate JWT header (`typ: oauth-id-jag+jwt`)
- [ ] Validate signature via IdP JWKS
- [ ] Validate required claims: `iss`, `sub`, `aud`, `client_id`, `exp`, `iat`, `jti`
- [ ] Map subject to Sentry user via SSO identity
- [ ] **ID-JAG Validation**
- [ ] Verify `aud` matches Sentry issuer
- [ ] Verify `client_id` matches request authentication
- [ ] Implement replay prevention via `jti` tracking
- [ ] Scope intersection (ID-JAG × request × client × user)
- [ ] **Trusted IdP Configuration**
- [ ] Model for trusted IdP registration (`TrustedIdentityProvider`)
- [ ] JWKS fetching with caching
- [ ] Subject-to-user mapping via AuthIdentity
- [ ] **Security**
- [ ] Confidential clients only
- [ ] Audit logging
- [ ] No refresh tokens (per spec §4.4.3)
### P1 - High
- [ ] **OAuth Metadata** (`/.well-known/oauth-authorization-server`)
- [ ] Advertise supported grant types
- [ ] Document PKCE, scopes, auth methods
- [ ] **Self-Service IdP Management UI**
- [ ] Register trusted IdPs in org settings
- [ ] Configure claim mappings
- [ ] Test JWKS connectivity
- [ ] **Error Handling** (RFC 6749 §5.2)
- [ ] Proper error codes for all failure modes
- [ ] Descriptive error messages
- [ ] **Testing**
- [ ] Unit tests for JWT validation
- [ ] Integration tests with mock IdP
- [ ] Key rotation handling
### P2 - Medium
- [ ] **JWKS Endpoint** (`/.well-known/jwks.json`)
- [ ] For mutual trust scenarios
- [ ] Key rotation support
- [ ] **Monitoring**
- [ ] Metrics for ID-JAG grants
- [ ] Alerting on validation failures
## Technical Details
| Setting | Value | Rationale |
| -- | -- | -- |
| Token Lifetime | 1 day (86400s) | No refresh tokens per spec |
| Org Scoping | Required | Via SSO identity mapping |
| IdP Registration | Self-service UI | Similar to current SSO setup |
| Refresh Tokens | Not issued | Spec §4.4.3 recommendation |
## Files to Modify
**Extend Existing:**
* `src/sentry/sentry_apps/token_exchange/util.py` - Add RFC 7523 grant type constant
* `src/sentry/sentry_apps/api/authentication.py` - Extend JWT validation for JWKS
* `src/sentry/web/frontend/oauth_token.py` - Add JWT bearer grant handler
* `src/sentry/utils/jwt.py` - Add JWKS fetching/caching
**New Files:**
* `src/sentry/models/trustedidentityprovider.py` - Trusted IdP model
* `src/sentry/sentry_apps/token_exchange/idjag_exchanger.py` - ID-JAG exchanger (follows `GrantExchanger` pattern)
**Patterns to Follow:**
* `JWTClientSecretAuthentication` - existing JWT validation with jti replay prevention
* `GrantExchanger` - token exchange pattern
## Spec References
* [ID-JAG Draft Spec]()
* [RFC 7523 - JWT Bearer Grant]()
* [RFC 8693 - Token Exchange]()
* [RFC 8414 - OAuth Metadata]()
Contributor guide
Assessment
This issue has not been assessed yet.