Authentication for satellite apps
Let the apps in your catalog trust Frontdoor sign-in with a shared cookie, a forwarded token or token introspection.
On this page
A satellite app is an app in the Frontdoor catalog that relies on Frontdoor for authentication. Admins pick its connection mode in the app editor (see Apps and connection modes); this page covers what the satellite has to do.
Choose a pattern
Pick the most restrictive pattern that fits your deployment.
| Pattern | When to use | What the satellite needs |
|---|---|---|
Shared cookie (mode=shared-cookie) |
The satellite is hosted under a subdomain of BASE_DOMAIN. |
Read the frontdoor_token httpOnly cookie and verify it locally with the shared JWT_SECRET. |
Redirect with shared secret (mode=redirect) |
The satellite is on a different domain, run by the same team. | Receive the short-lived token by GET query string or POST form, and verify it locally with the shared JWT_SECRET. |
Redirect with introspection (mode=redirect) |
The satellite is on a different domain and should not hold Frontdoor's secret: a third party, a lower-trust environment, or to limit the damage of a leak. | Receive the short-lived token, then POST it to /api/auth/verify-sso-token with its own slug as expected_aud. No shared secret. |
Both redirect patterns use the same app mode (mode=redirect); they differ only in how the satellite verifies the token.
Sharing the secret
An app that holds JWT_SECRET can verify Frontdoor tokens, but it could also sign them, including session tokens. Share the secret only with fully trusted apps and use introspection for the others.
Frontdoor accepts as sessions only tokens signed with HS256, carrying its issuer (JWT_ISSUER, default frontdoor) and no audience. A satellite that verifies tokens locally must expect the same issuer.
Verify a token with introspection
POST /api/auth/verify-sso-token is a server-to-server introspection endpoint, inspired by RFC 7662 and scoped to this flow. In one call Frontdoor checks the signature, expiration, issuer, audience, that the user is active and that the app is active.
You do not need an API key: holding a valid token for the requested expected_aud is the authorization.
curl -sX POST https://frontdoor.contoso.com/api/auth/verify-sso-token \
-H 'Content-Type: application/json' \
-d '{"token":"<jwt>","expected_aud":"<your-app-slug>"}'
A valid token returns 200:
{
"valid": true,
"user": { "id": "...", "email": "...", "name": "...", "role": "user" },
"aud": "<your-app-slug>",
"exp": 1745740300
}
Errors
| Status | error |
Meaning |
|---|---|---|
| 400 | bad_request |
token or expected_aud is missing or malformed (slug format). |
| 401 | invalid_token |
Bad signature or expired token (intentionally indistinguishable). |
| 401 | invalid_issuer |
The token was not issued by this Frontdoor. |
| 401 | user_not_found_or_inactive |
The token's sub does not match an active user. |
| 403 | audience_mismatch |
The token was replayed across apps. Frontdoor logs the caller as a warning. |
| 403 | app_inactive |
expected_aud matches an app that has been deactivated. |
| 429 | too_many_requests |
Rate limit tripped (120 requests per minute per IP). |
Scope the local session
Use exp to limit the satellite's own session, so it never outlives the Frontdoor token:
local session lifetime = min(default_session_ttl, exp - now)
Check the session from another origin
A page that only needs to know whether the user is signed in, without being an app in the catalog, can call /api/auth/me with credentials: 'include' once its origin is in CORS_ALLOWED_ORIGINS. See Cross-origin session checks.
Impersonation and satellites
When an admin acts as a user in Frontdoor, the session lives in a separate host-only cookie (frontdoor_impersonation) used only on requests from Frontdoor itself. The shared frontdoor_token cookie never changes, so shared-cookie satellites and cross-origin session checks keep seeing the admin, never the impersonated user. While impersonating, apps cannot be opened and no SSO token is issued.