Direct External Authentication
Fanoni supports authenticating users directly with an external Identity Provider (IDP) access token, without requiring a token exchange or authorization code flow. This is useful when your application already holds a valid JWT from an external IDP and wants to access the Fanoni API directly.
This feature requires super admin privileges to configure externalAuthProviders in the server config, which is only available on self-hosted Fanoni deployments. If you are using Fanoni's cloud-hosted service and need this capability, please contact Fanoni support.
Overview
When a user presents a JWT issued by a configured external auth provider, Fanoni can:
- Validate the token against the IDP's userinfo endpoint
- Identify the user from claims in the token
- Return Fanoni auth credentials for subsequent API access
There are two ways to identify the user from the token:
| Method | JWT Claim | Lookup | Best for |
|---|---|---|---|
| FHIR User | fhirUser | Profile reference or search | SMART-on-FHIR compliant IDPs |
| Subject | sub | ProjectMembership.externalId | Standard OIDC IDPs |
If both fhirUser and sub are present, the fhirUser claim takes precedence.
Server Configuration
Add external auth providers to your Fanoni server configuration:
{
"externalAuthProviders": [
{
"issuer": "https://your-idp.example.com",
"userInfoUrl": "https://your-idp.example.com/oauth2/userinfo"
}
]
}
| Field | Description |
|---|---|
issuer | The iss claim value in JWTs from this IDP |
userInfoUrl | The IDP's userinfo endpoint, used to validate tokens |
Using the fhirUser Claim
The fhirUser claim contains a FHIR resource reference identifying the user's profile. It can be provided in several formats:
- Direct reference:
Practitioner/abc123 - Search string:
Practitioner?identifier=1234567890 - Absolute URL:
https://idp.example.com/fhir/Practitioner?identifier=1234567890
Some IDPs place custom claims inside an ext block. Fanoni also checks ext.fhirUser for compatibility.
How it works
- Fanoni extracts the
fhirUserclaim from the JWT - Validates the token against the IDP's userinfo endpoint
- Searches for the FHIR profile resource matching the claim
- Finds the
ProjectMembershipassociated with that profile - Returns auth credentials scoped to that membership
Using the sub Claim
The sub (subject) claim is a standard JWT claim (RFC 7519) present in virtually all JWTs. When no fhirUser claim is present, Fanoni uses the sub claim to look up a ProjectMembership by its externalId field.
Setup
- Configure the external auth provider in your server config (see above)
- Invite users with an
externalIdmatching their IDPsubvalue:
curl 'https://BASE_URL/admin/projects/PROJECT_ID/invite' \
-H 'Authorization: Bearer ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
--data-raw '{
"resourceType": "Practitioner",
"firstName": "Jane",
"lastName": "Smith",
"externalId": "IDP_SUBJECT_ID"
}'
Replace BASE_URL, PROJECT_ID, and ACCESS_TOKEN with your actual values.
The externalId value should match the sub claim that the IDP assigns to this user.
To find a user's sub value, decode the JWT from your IDP or check the IDP's user management console. For Auth0, the subject may be prefixed with the identity provider (e.g., google-oauth2|110925489055200000000). Use the full value as the externalId.
How it works
- Fanoni parses the JWT and finds no
fhirUserclaim - Extracts the
subclaim - Validates the token against the IDP's userinfo endpoint
- Searches for a
ProjectMembershipwhereexternalIdmatches thesubvalue - Returns auth credentials scoped to that membership
The externalId must be unique across all project memberships. If multiple memberships share the same externalId, authentication will fail with a 401 response to prevent ambiguity.
Making Requests
Once configured, make requests to the Fanoni FHIR API using the external IDP token directly:
curl 'https://${baseUrl}/oauth2/userinfo' \
-H 'Authorization: Bearer ${externalAccessToken}'
A successful response returns the user's profile information and Fanoni login credentials. Subsequent requests to the FHIR API can use the returned Fanoni access token.
Fanoni caches external auth results in Redis for 1 hour to minimize calls to the IDP's userinfo endpoint.
Comparison with Token Exchange
| Direct External Auth | Token Exchange | |
|---|---|---|
| Endpoint | /oauth2/userinfo | /oauth2/token |
| Configuration | Server-level externalAuthProviders | Per-ClientApplication identity provider |
| Token format | Uses external JWT directly | Exchanges for Fanoni access token |
| User lookup | fhirUser claim or sub / externalId | Email or sub (via useSubject flag) |
Choose Direct External Auth when you want to use external JWTs directly without an explicit token exchange step. Choose Token Exchange when you need a standard Fanoni access token or when the auth flow is scoped to a specific ClientApplication.