DependencyTrack / DependencyTrack/dependency-track
Infinite redirect loop after successful OIDC authentication with Okta (Frontend 4.13.1 / Chart 0.39.0-0.40.0-0.41.0)
- Dominant language
- Java
- Stars
- 4.2k
- Forks
- 811
- Avg merge
- 8h 39m
- Merged PRs (30d)
- 237
Description
### Current Behavior
After successful Okta authentication, the frontend enters an infinite redirect loop instead of completing the login process. The browser console shows:
`RangeError: Maximum call stack size exceeded
at router.replace (chunk-vendors.c39ed462.js:63)
at Vue router navigation (app.72a50f68.js:1)`
The authentication flow completes successfully up to token exchange with Okta, but then the Vue router enters a recursive loop.
### Steps to Reproduce
Environment
• Dependency-Track Helm Chart: 0.39.0, 0.40.0 and 0.41.0 (tested all - same issue)
• Frontend Image: dependencytrack/frontend:4.13.1 and 4.12.0 (tested both - same issue)
• API Server Image: dependencytrack/apiserver:4.13.1
• IdP: Okta with default authorization server
• Deployment: Kubernetes (AWS EKS)
• Browser: Chrome 143.0.0.0
Okta Configuration
• App Type: Single-Page Application (SPA, public client)
• Client ID: 0xxxxxxxxxxx
• Issuer: https://my.okta.com/oauth2/default
• Sign-in redirect URI: https://dependency-track.my.syte/static/oidc-callback.html
• Sign-out redirect URI: https://dependency-track.my.syte
• Trusted Origin: https://dependency-track.my.syte (CORS + Redirect enabled)
• Grant types: Authorization Code only (no Implicit flow)
API Server Configuration (Backend OIDC)
`env:
- name: ALPINE_OIDC_ENABLED
value: "true"
- name: ALPINE_OIDC_ISSUER
value: "https://my.okta.com/oauth2/default"
- name: ALPINE_OIDC_CLIENT_ID
value: "0xxxxxxxxxxx"
- name: ALPINE_OIDC_USERNAME_CLAIM
value: "email"
- name: ALPINE_OIDC_TEAMS_CLAIM
value: "groups"
- name: ALPINE_OIDC_USER_PROVISIONING
value: "true"
- name: ALPINE_OIDC_TEAM_SYNCHRONIZATION
value: "true"
- name: ALPINE_SECRET_KEY_PASSWORD
valueFrom:
secretKeyRef:
name: dependency-track-oidc-env
key: ALPINE_SECRET_KEY_PASSWORD`
Backend OIDC is working: curl https://dependency-track.my.syte/api/v1/oidc/available returns true.
Frontend Configuration (via environment variables)
`kubectl set env deployment/dependency-track-frontend -n dependency-track \
API_BASE_URL="" \
OIDC_ISSUER="https://my.okta.com/oauth2/default" \
OIDC_CLIENT_ID="0xxxxxxxxxxx" \
OIDC_SCOPE="openid profile email"`
Resulting config.json:
`{
"API_BASE_URL": "",
"API_WITH_CREDENTIALS": null,
"OIDC_CLIENT_ID": "0xxxxxxxxxxx",
"OIDC_FLOW": null,
"OIDC_ISSUER": "https://my.okta.com/oauth2/default",
"OIDC_LOGIN_BUTTON_TEXT": null,
"OIDC_SCOPE": "openid profile email"
}`
Reproduction Steps
1. Navigate to https://dependency-track.my.syte
2. Click "OpenID" button on login page
3. Authenticate successfully with Okta
4. Browser redirects to /static/oidc-callback.html?code=...&state=...
5. BUG OCCURS: Infinite redirect loop starts
Observed Network Activity
Frontend nginx access log shows successful callback:
`GET /static/oidc-callback.html?code=mjyyyyyyyyyyyyyyyyyyyy=cdzzzzzzzzzzzzzzzzzz HTTP/1.1" 200
GET /static/js/oidc-client.min.js HTTP/1.1" 200
GET /static/config.json HTTP/1.1" 200`
Browser Network tab shows:
• ✓ GET /.well-known/openid-configuration (200)
• ✓ POST /oauth2/default/v1/token (200, returns tokens)
• ✓ GET /static/config.json (200)
• ✗ Missing: POST /api/v1/user/oidc/login (never called)
Browser localStorage shows tokens were successfully stored:
`{
"oidc.user:https://my.okta.com/oauth2/default:0xxxxxxxxxxx": {
"id_token": "eyJraWQiOi...",
"access_token": "eyJraWQiOi...",
"token_type": "Bearer",
"scope": "email profile openid",
"profile": {
"sub": "00uthyuo38k1OeZoR417",
"name": "Oleg Pchelintsev",
"email": "Pchelintsev.Oleg@my.syte",
"groups": ["Everyone"]
},
"expires_at": 1769098211
}
}`
The frontend successfully obtains tokens but never calls the API server to complete authentication.
Browser Console Error
`chunk-vendors.c39ed462.js:63 RangeError: Maximum call stack size exceeded
o @ chunk-vendors.c39ed462.js:63
h @ chunk-vendors.c39ed462.js:63
r @ chunk-vendors.c39ed462.js:63
Gt @ chunk-vendors.c39ed462.js:63
te.confirmTransition @ chunk-vendors.c39ed462.js:63
te.transitionTo @ chunk-vendors.c39ed462.js:63
e.replace @ chunk-vendors.c39ed462.js:63
(anonymous) @ chunk-vendors.c39ed462.js:63
(anonymous) @ app.72a50f68.js:1
... (repeats until stack overflow)`
The Vue router's router.replace() method calls itself recursively until the stack overflows.
Attempted Workarounds
1. Tried Implicit Flow
Set OIDC_FLOW="implicit" in frontend config.
Result: White screen with error:
`ErrorResponse: The response type is not supported by the authorization server. Configured response types: [code].`
(Okta app only supports Authorization Code flow)
2 .Tested Multiple Versions
• Chart 0.39.0 with frontend 4.12.1: Same bug
• Chart 0.39.0 with frontend 4.13.1: Same bug
• Chart 0.40.0 with frontend 4.12.0: Same bug
• Chart 0.40.0 with frontend 4.13.0: Same bug
• Chart 0.41.0 with frontend 4.13.0: Same bug
• Chart 0.41.0 with frontend snapshot: Same bug
3 .Verified API Endpoint
Tested /api/v1/user/oidc/login endpoint manually:
`kubectl run curl-test --image=curlimages/curl:latest -n dependency-track --rm -it --restart=Never -- \
curl -v -X POST http://dependency-track-api-server:8080/api/v1/user/oidc/login \
-H "Content-Type: application/json" \
-d '{"idToken": "eyJ..."}'`
Result: 415 Unsupported Media Type (unclear what format API expects)
Tried with Authorization header:
`curl -v http://dependency-track-api-server:8080/api/v1/user/oidc/login \
-H "Authorization: Bearer eyJ..."`
Result: 405 Method Not Allowed with Allow: POST,OPTIONS
The API endpoint exists and accepts POST, but the frontend never reaches it due to the redirect loop.
Additional Context
• API server logs show no OIDC-related errors
• Clearing browser cache/cookies does not help
• Issue is consistent across multiple developer machines
• Bug appears to be in frontend JavaScript between token exchange and API login call
Proposed Solution
The infinite redirect loop suggests an issue in the OIDC callback handling logic in the frontend, likely in:
• /static/oidc-callback.html
• Vue router navigation guards
• OIDC state management after token receipt
The frontend should call /api/v1/user/oidc/login with the id_token after successful token exchange, but this call never happens.
Environment Details
`Helm Chart: 0.39.0 / 0.40.0 / 0.41.0
Frontend: dependencytrack/frontend:4.13.1 / 4.12.0 / snapshot
API Server: dependencytrack/apiserver:4.13.1
Kubernetes: AWS EKS
Browser: Chrome 143.0.0.0 on macOS
IdP: Okta (default authorization server)`
### Expected Behavior
After successful OIDC callback, the frontend should:
1. Receive the authorization code
2. Exchange code for tokens with Okta (✓ working)
3. Call /api/v1/user/oidc/login with the id_token
4. Redirect to /dashboard
### Dependency-Track Version
4.13.1
### Dependency-Track Distribution
Container Image
### Database Server
PostgreSQL
### Database Server Version
17.5
### Browser
Google Chrome
### Checklist
- [x] I have read and understand the [contributing guidelines](https://github.com/DependencyTrack/dependency-track/blob/master/CONTRIBUTING.md#filing-issues)
- [x] I have checked the [existing issues](https://github.com/DependencyTrack/dependency-track/issues) for whether this defect was already reported
Contributor guide
Assessment
This issue has not been assessed yet.