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
Section titled “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
Section titled “User resolution”When a user authenticates through a federation provider, Autentico resolves the local user account in this order:
- Existing federated identity – if the (provider_id, provider_sub) pair is already linked to a local user, that user is used
- Verified email match – if both the external provider and the local account have verified the same email address, the accounts are automatically linked
- New account – if no match is found, a new local user is created with a derived username and a random unusable password
Managing providers via admin API
Section titled “Managing providers via admin API”All federation provider endpoints require admin authentication.
| Method | Endpoint | Description |
|---|---|---|
GET |
/admin/api/federation |
List all providers (paginated) |
POST |
/admin/api/federation |
Create 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
Section titled “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
Section titled “Provider fields”| Field | Required | Description |
|---|---|---|
id |
Yes | Unique slug identifier (e.g. google, github). Used in URLs. |
name |
Yes | Display name shown on the login page |
issuer |
Yes | OIDC issuer URL (must support /.well-known/openid-configuration) |
client_id |
Yes | Client ID registered with the external provider |
client_secret |
Yes | Client secret from the external provider |
icon_svg |
No | SVG markup for the provider icon on the login page |
enabled |
No | Whether the provider is active (default: true) |
sort_order |
No | Display order on the login page (lower numbers first) |
List providers
Section titled “List providers”curl "https://auth.example.com/admin/api/federation?sort=sort_order&order=asc" \ -H "Authorization: Bearer $ADMIN_TOKEN"Supports query parameters:
| Parameter | Description |
|---|---|
sort |
Sort field: name, issuer, client_id, sort_order, enabled, created_at |
order |
Sort order: asc (default), desc |
search |
Search across name, issuer, client_id |
enabled |
Filter by enabled status: 1 or 0 |
limit |
Max results per page (1–100, default 100) |
offset |
Number of results to skip (default 0) |
Update a provider
Section titled “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
Section titled “Delete a provider”curl -X DELETE https://auth.example.com/admin/api/federation/google \ -H "Authorization: Bearer $ADMIN_TOKEN"Federation endpoints (public)
Section titled “Federation endpoints (public)”These endpoints are used during the login flow and are not authenticated.
| Method | Endpoint | Description |
|---|---|---|
GET |
{oauth_path}/federation/{id}/begin |
Start federation login (redirects to external provider) |
GET |
{oauth_path}/federation/{id}/callback |
Handle callback from external provider |
GET |
{oauth_path}/federation/{id}/icon |
Serve the provider’s SVG icon |
Begin federation login
Section titled “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=S256Provider icon security
Section titled “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+xmland loaded via<img>tags, which disables script execution - A restrictive
Content-Security-Policyheader (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
Section titled “Database tables”federation_providers table
Section titled “federation_providers table”| Column | Type | Description |
|---|---|---|
id |
TEXT | Primary key (admin-chosen slug) |
name |
TEXT | Display name |
issuer |
TEXT | OIDC issuer URL |
client_id |
TEXT | OAuth2 client ID at the external provider |
client_secret |
TEXT | OAuth2 client secret |
icon_svg |
TEXT | SVG markup (nullable) |
enabled |
BOOLEAN | Whether the provider is active |
sort_order |
INTEGER | Display order |
created_at |
DATETIME | Creation timestamp |
federated_identities table
Section titled “federated_identities table”| Column | Type | Description |
|---|---|---|
id |
TEXT | Primary key (xid) |
provider_id |
TEXT | Foreign key to federation_providers.id |
provider_user_id |
TEXT | The sub claim from the external provider |
user_id |
TEXT | Foreign key to users.id |
email |
TEXT | Email from the external provider (nullable) |
created_at |
DATETIME | When the link was created |
SSRF protection
Section titled “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.