Skip to main content

Federation / Social Login

Federation allows users to authenticate with external OIDC identity providers (such as Google, GitHub, or any OIDC-compliant provider) instead of using a local username and password. When a user logs in via a federation provider, Autentico creates or links a local user account and issues tokens as usual.

How it works​

sequenceDiagram
actor User
participant Browser
participant IdP as Autentico
participant ExtIdP as External Provider

User->>Browser: Click "Sign in with Google"
Browser->>IdP: GET /oauth2/federation/{id}/begin?client_id=X&...
IdP->>Browser: 302 -> External provider authorize URL
Browser->>ExtIdP: Authorization request
ExtIdP->>Browser: Login + consent at external provider
Browser->>IdP: GET /oauth2/federation/{id}/callback?code=...&state=...
IdP->>ExtIdP: Exchange code for tokens
ExtIdP->>IdP: ID token + access token
IdP->>IdP: Verify ID token, resolve local user
IdP->>Browser: 302 -> redirect_uri?code=AUTH_CODE

The OAuth2 authorization parameters (client_id, redirect_uri, scope, state, code_challenge) are preserved through the federation flow using an HMAC-signed state parameter.

User resolution​

When a user authenticates through a federation provider, Autentico resolves the local user account in this order:

  1. Existing federated identity -- if the (provider_id, provider_sub) pair is already linked to a local user, that user is used
  2. Verified email match -- if both the external provider and the local account have verified the same email address, the accounts are automatically linked
  3. New account -- if no match is found, a new local user is created with a derived username and a random unusable password
note

Auto-linking by email only occurs when the email is verified on both sides (the external provider reports email_verified: true and the local account has a verified email). This prevents account takeover via unverified email claims.

Managing providers via admin API​

All federation provider endpoints require admin authentication.

MethodEndpointDescription
GET/admin/api/federationList all providers (paginated)
POST/admin/api/federationCreate a new provider
GET/admin/api/federation/{id}Get a provider by ID
PUT/admin/api/federation/{id}Update a provider
DELETE/admin/api/federation/{id}Delete a provider

Create a provider​

curl -X POST https://auth.example.com/admin/api/federation \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"id": "google",
"name": "Google",
"issuer": "https://accounts.google.com",
"client_id": "your-google-client-id",
"client_secret": "your-google-client-secret",
"enabled": true,
"sort_order": 1
}'

Provider fields​

FieldRequiredDescription
idYesUnique slug identifier (e.g. google, github). Used in URLs.
nameYesDisplay name shown on the login page
issuerYesOIDC issuer URL (must support /.well-known/openid-configuration)
client_idYesClient ID registered with the external provider
client_secretYesClient secret from the external provider
icon_svgNoSVG markup for the provider icon on the login page
enabledNoWhether the provider is active (default: true)
sort_orderNoDisplay order on the login page (lower numbers first)

List providers​

curl "https://auth.example.com/admin/api/federation?sort=sort_order&order=asc" \
-H "Authorization: Bearer $ADMIN_TOKEN"

Supports query parameters:

ParameterDescription
sortSort field: name, issuer, client_id, sort_order, enabled, created_at
orderSort order: asc (default), desc
searchSearch across name, issuer, client_id
enabledFilter by enabled status: 1 or 0
limitMax results per page (1--100, default 100)
offsetNumber of results to skip (default 0)

Update a provider​

curl -X PUT https://auth.example.com/admin/api/federation/google \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Google",
"issuer": "https://accounts.google.com",
"client_id": "updated-client-id",
"client_secret": "updated-secret",
"enabled": true,
"sort_order": 1
}'

Delete a provider​

curl -X DELETE https://auth.example.com/admin/api/federation/google \
-H "Authorization: Bearer $ADMIN_TOKEN"

Federation endpoints (public)​

These endpoints are used during the login flow and are not authenticated.

MethodEndpointDescription
GET{oauth_path}/federation/{id}/beginStart federation login (redirects to external provider)
GET{oauth_path}/federation/{id}/callbackHandle callback from external provider
GET{oauth_path}/federation/{id}/iconServe the provider's SVG icon

Begin federation login​

The begin endpoint accepts the standard OAuth2 authorization parameters as query strings so they can be preserved through the external provider redirect:

GET /oauth2/federation/google/begin?client_id=my-app&redirect_uri=https://app.example.com/callback&scope=openid+profile+email&state=abc123&code_challenge=...&code_challenge_method=S256

Provider icon security​

Provider icons (SVG) are served via a dedicated endpoint ({oauth_path}/federation/{id}/icon) with the following security measures:

  • SVGs are served with Content-Type: image/svg+xml and loaded via <img> tags, which disables script execution
  • A restrictive Content-Security-Policy header (default-src 'none'; style-src 'unsafe-inline'; sandbox) is set on direct navigation
  • Icons are cached with ETags and a 5-minute max-age

Database tables​

federation_providers table​

ColumnTypeDescription
idTEXTPrimary key (admin-chosen slug)
nameTEXTDisplay name
issuerTEXTOIDC issuer URL
client_idTEXTOAuth2 client ID at the external provider
client_secretTEXTOAuth2 client secret
icon_svgTEXTSVG markup (nullable)
enabledBOOLEANWhether the provider is active
sort_orderINTEGERDisplay order
created_atDATETIMECreation timestamp

federated_identities table​

ColumnTypeDescription
idTEXTPrimary key (xid)
provider_idTEXTForeign key to federation_providers.id
provider_user_idTEXTThe sub claim from the external provider
user_idTEXTForeign key to users.id
emailTEXTEmail from the external provider (nullable)
created_atDATETIMEWhen the link was created

SSRF protection​

When Autentico communicates with external providers (OIDC discovery and token exchange), it uses a restricted HTTP client that:

  • Blocks redirects to private/loopback IP ranges (127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, link-local, IPv6 equivalents)
  • Limits the number of redirects to 5
  • Enforces a 10-second timeout

This prevents SSRF attacks where a malicious issuer URL could be used to probe internal infrastructure.