Forge external auth completes successfully, but outboundAuth/finish tab does not close and UI shows “auth window closed”
Hi,
I’m seeing an issue with Forge external authentication and I’d like to know whether anyone else has run into something similar.
I have a Forge Jira issue panel using an OAuth2 provider configured against Microsoft Entra ID. The app requests an access token for my own backend API, not Microsoft Graph.
The provider is configured roughly like this:
providers:
auth:
- key: microsoft-backend
name: Microsoft Backend
type: oauth2
clientId: <client-id>
scopes:
- openid
- profile
- email
- api://<client-id>/access_as_user
remotes:
- portal-backend
bearerMethod: authorization-header
actions:
authorization:
remote: microsoft-login
path: /<tenant-id>/oauth2/v2.0/authorize
exchange:
remote: microsoft-login
path: /<tenant-id>/oauth2/v2.0/token
refreshToken:
remote: microsoft-login
path: /<tenant-id>/oauth2/v2.0/token
retrieveProfile:
remote: portal-backend
path: /api/auth/profile
resolvers:
id: id
displayName: displayName
remotes:
- key: microsoft-login
baseUrl: https://login.microsoftonline.com
- key: portal-backend
baseUrl: https://<my-backend-domain>
My backend validates the Microsoft JWT using Microsoft JWKS and checks:
signature
exp / nbf / iat
aud = api://<client-id>
tid / issuer
scp contains access_as_user
The retrieveProfile endpoint is intentionally simple. Forge calls it with the bearer token, my backend validates the token, extracts claims from it, and returns:
{
"id": "<oid-or-sub>",
"displayName": "<name-or-email>",
"email": "<email-or-upn>",
"tenantId": "...",
"objectId": "..."
}
From the backend logs, everything looks successful:
JWT valid
aud=api://<client-id>
scope=access_as_user
GET /api/auth/profile
[AUTH PROFILE] Returning Forge profile id=... displayName=...
Also, if I manually refresh the Jira issue panel after the auth flow, the app correctly detects that the user is authenticated. So the credentials seem to be stored by Forge.
The problem is that the auth browser window/tab remains stuck on:
https://id.atlassian.com/outboundAuth/finish?code=...&state=...
and the Jira UI shows a Forge banner/message along the lines of “auth window closed”. It looks like the OAuth flow has actually completed, but Forge does not close the outboundAuth/finish window or notify/resume the panel cleanly.
I have added polling in the issue panel after calling requestCredentials(), so the panel can detect hasCredentials() eventually, but the Forge-auth window behavior still looks broken/confusing for the user.
Has anyone seen this with Forge external auth, especially with a custom backend API scope like:
api://<client-id>/access_as_user
rather than Microsoft Graph scopes like User.Read?
Is there anything specific required in the retrieveProfile response or provider configuration to make outboundAuth/finish close reliably? Or is this a known limitation/bug depending on browser, iframe, popup handling, or environment?
Any pointers would be appreciated.