Skip to main content
Anchor supports OpenID Connect (OIDC) authentication, enabling single sign-on with external identity providers like Keycloak, Auth0, Okta, Google, Azure AD, and more.

Overview

OIDC authentication provides:
  • Single Sign-On: Users authenticate through your identity provider
  • Automatic Account Linking: Matches users by email and links OIDC identity
  • Profile Sync: Name and avatar are synchronized from the provider
  • PKCE Support: Works with public clients (no client secret required)
  • Flexible Configuration: Configure via environment variables or admin UI

Configuration Methods

Configure OIDC using environment variables in your .env file:
.env
# Application URL for callbacks
APP_URL=http://localhost:3000

# OIDC Configuration
OIDC_ENABLED=true
OIDC_PROVIDER_NAME="Pocket ID"
OIDC_ISSUER_URL=https://auth.example.com
OIDC_CLIENT_ID=your-client-id
OIDC_CLIENT_SECRET=your-client-secret  # Optional for PKCE

# Optional: Hide local login form
DISABLE_INTERNAL_AUTH=false
When OIDC settings are configured via environment variables, they cannot be changed through the admin UI.

Required Configuration

ParameterDescriptionRequired
OIDC_ENABLEDEnable/disable OIDC authenticationYes
OIDC_ISSUER_URLYour identity provider’s issuer URLYes
OIDC_CLIENT_IDOAuth 2.0 client IDYes
OIDC_CLIENT_SECRETOAuth 2.0 client secretNo*
OIDC_PROVIDER_NAMEDisplay name for the providerNo
DISABLE_INTERNAL_AUTHHide local login formNo
APP_URLBase URL for callbacksYes
*Client secret is optional when using PKCE (Proof Key for Code Exchange) for public clients like mobile apps.

Callback URL

Configure your identity provider with this callback URL:
{APP_URL}/api/auth/oidc/callback
Examples:
  • Development: http://localhost:3000/api/auth/oidc/callback
  • Production: https://anchor.yourdomain.com/api/auth/oidc/callback

Provider-Specific Setup

1

Create OAuth Application

In Pocket ID, navigate to Applications and create a new OAuth application.
2

Configure Redirect URI

Add the callback URL:
http://localhost:3000/api/auth/oidc/callback
3

Get Credentials

Copy the Client ID and optionally the Client Secret.
4

Configure Anchor

.env
OIDC_ENABLED=true
OIDC_PROVIDER_NAME="Pocket ID"
OIDC_ISSUER_URL=https://auth.pocketid.app
OIDC_CLIENT_ID=your-client-id
OIDC_CLIENT_SECRET=your-client-secret

Authentication Flow

1

User initiates OIDC login

The user clicks “Sign in with [Provider]” button, which redirects to:
GET /api/auth/oidc/initiate?redirect=/dashboard
Optional redirect parameter specifies where to redirect after successful login.
2

Authorization request

Anchor generates:
  • CSRF protection state token
  • PKCE code challenge (if no client secret)
  • Stores state in memory with redirect URL
User is redirected to the identity provider’s authorization endpoint.
3

User authenticates

The user logs in at the identity provider and grants consent.
4

Callback with authorization code

Provider redirects back to:
GET /api/auth/oidc/callback?code=...&state=...
5

Token exchange

Anchor:
  1. Validates the state parameter
  2. Exchanges authorization code for tokens
  3. Fetches user information from provider
  4. Extracts claims (email, name, subject, picture)
6

User provisioning

Anchor finds or creates the user:
User with matching oidcSubject is found and updated with latest profile info.
7

Generate app tokens

Anchor creates its own access and refresh tokens for the user.
8

Redirect to frontend

User is redirected to:
{APP_URL}/login?code={exchange_code}&redirect=/dashboard
The frontend exchanges the one-time code for actual tokens.
9

Frontend token exchange

Frontend Exchange
POST /api/auth/oidc/exchange
Content-Type: application/json

{
  "code": "exchange-code-from-url"
}
Response:
{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "refresh_token": "a8f5d234b9c1e7f3a2d6...",
  "user": {
    "id": "uuid",
    "email": "[email protected]",
    "name": "John Doe",
    "profileImage": "/uploads/profiles/uuid-oidc-123.jpg",
    "isAdmin": false,
    "status": "active"
  },
  "redirectUrl": "/dashboard"
}

Mobile Authentication

For mobile apps, use the direct token exchange endpoint:
Mobile Login
POST /api/auth/oidc/exchange/mobile
Content-Type: application/json

{
  "access_token": "idp-access-token-from-mobile-sdk"
}
This endpoint accepts the identity provider’s access token directly and returns Anchor tokens.

Account Linking Behavior

When a user logs in with OIDC and an account with the same email exists:
  • If the account has no OIDC subject → Link is created automatically
  • If the account has a different OIDC subject → Error (email already linked)
  • User can now authenticate with either local credentials or OIDC
Users created via OIDC have no password:
  • Cannot use local authentication endpoint
  • Password change endpoint returns error
  • Must authenticate through OIDC provider
  • Linked accounts retain their password capability
On each OIDC login:
  • Display name is updated from provider
  • Profile picture is downloaded if provided
  • Old OIDC-downloaded avatars are replaced
  • Manually uploaded avatars are preserved

Disabling Local Authentication

For SSO-only deployments, disable the local login form:
.env
DISABLE_INTERNAL_AUTH=true
Ensure OIDC is properly configured before disabling local auth, or you may lock yourself out.

Required OIDC Claims

Anchor requires these standard OIDC claims:
ClaimSourceUsage
subID token or userinfoUnique user identifier
emailID token or userinfoUser’s email address
nameID token or userinfoDisplay name (fallback to username or email)
pictureID token or userinfoProfile avatar URL (optional)

Checking OIDC Configuration

Get current OIDC settings:
Check Config
curl http://localhost:3000/api/auth/oidc/config
Response:
{
  "enabled": true,
  "providerName": "Pocket ID",
  "issuerUrl": "https://auth.example.com",
  "clientId": "your-client-id",
  "disableInternalAuth": false
}

Troubleshooting

Cause: State token expired (60 seconds) or invalidSolution: Try logging in again. Ensure system clocks are synchronized.
Cause: Exchange code expired (30 seconds) or already usedSolution: Exchange codes are single-use. Return to login page and try again.
Cause: Email exists with different OIDC subjectSolution: Use the original OIDC provider or contact administrator to unlink.
Cause: Provider missing email or sub claimSolution: Check identity provider configuration. Ensure email scope is requested.

Implementation Reference

The OIDC implementation can be found in:
  • Controller: server/src/auth/oidc/oidc.controller.ts
  • Service: server/src/auth/oidc/oidc.service.ts
  • Config: server/src/auth/oidc/oidc-config.service.ts
  • User linking: server/src/auth/oidc/oidc-user.service.ts

Next Steps

User Management

Configure registration modes for OIDC users

Local Auth

Configure local authentication alongside OIDC

Build docs developers (and LLMs) love