Authentication Methods
Anchor supports two authentication methods:
JWT Bearer Tokens - For web and mobile applications
API Tokens - For programmatic access and integrations
JWT Authentication
Include the JWT access token in the Authorization header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Token Lifecycle
Access Token : Short-lived (typically 15 minutes)
Refresh Token : Long-lived (90 days)
Use the refresh token to obtain new access tokens without re-authentication
API Token Authentication
For server-to-server or CLI integrations, use API tokens:
Authorization: Bearer your-api-token-here
API tokens do not expire but can be revoked or regenerated.
Check Registration Mode
curl -X GET http://localhost:3001/api/auth/registration-mode
Registration mode: disabled, enabled, or review
Register
Create a new user account. Returns tokens immediately if registration mode is enabled, or requires admin approval if mode is review.
curl -X POST http://localhost:3001/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "securepassword123",
"name": "John Doe"
}'
Password (minimum 8 characters)
User’s display name (max 100 characters, whitespace trimmed)
Active User
Pending Approval
{
"access_token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." ,
"refresh_token" : "a1b2c3d4e5f6..." ,
"user" : {
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"email" : "user@example.com" ,
"name" : "John Doe" ,
"profileImage" : null ,
"isAdmin" : false ,
"status" : "active" ,
"createdAt" : "2026-03-02T10:30:00.000Z" ,
"updatedAt" : "2026-03-02T10:30:00.000Z"
}
}
The first user to register automatically becomes an admin.
Login
Authenticate with email and password to receive JWT tokens.
curl -X POST http://localhost:3001/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "securepassword123"
}'
{
"access_token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." ,
"refresh_token" : "a1b2c3d4e5f6..." ,
"user" : {
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"email" : "user@example.com" ,
"name" : "John Doe" ,
"profileImage" : null ,
"isAdmin" : false ,
"status" : "active" ,
"createdAt" : "2026-03-02T10:30:00.000Z" ,
"updatedAt" : "2026-03-02T10:30:00.000Z"
}
}
Error Responses
{
"statusCode" : 401 ,
"message" : "Invalid credentials" ,
"error" : "Unauthorized"
}
{
"statusCode" : 403 ,
"message" : "Account is pending approval" ,
"error" : "Forbidden"
}
Refresh Token
Obtain a new access token using a refresh token.
curl -X POST http://localhost:3001/api/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "a1b2c3d4e5f6..."
}'
Valid refresh token from login or previous refresh
{
"access_token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." ,
"refresh_token" : "z9y8x7w6v5u4..."
}
Logout
Revoke a refresh token to log out.
curl -X POST http://localhost:3001/api/auth/logout \
-H "Content-Type: application/json" \
-d '{
"refreshToken": "a1b2c3d4e5f6..."
}'
Refresh token to revoke (optional)
Get Current User
Bearer token (JWT or API token)
curl -X GET http://localhost:3001/api/auth/me \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
{
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"email" : "user@example.com" ,
"name" : "John Doe" ,
"profileImage" : "/uploads/profiles/avatar.jpg" ,
"isAdmin" : false ,
"status" : "active" ,
"createdAt" : "2026-03-02T10:30:00.000Z" ,
"updatedAt" : "2026-03-02T10:30:00.000Z"
}
API Token Management
Get API Token
Retrieve your current API token.
curl -X GET http://localhost:3001/api/auth/api-token \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
{
"apiToken" : "ak_1234567890abcdef"
}
Regenerate API Token
Create a new API token, invalidating the previous one.
curl -X POST http://localhost:3001/api/auth/api-token/regenerate \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
{
"apiToken" : "ak_newtoken9876543210"
}
Revoke API Token
Delete your API token.
curl -X DELETE http://localhost:3001/api/auth/api-token \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
{
"message" : "API token revoked successfully"
}
Change Password
curl -X POST http://localhost:3001/api/auth/change-password \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
-H "Content-Type: application/json" \
-d '{
"currentPassword": "oldpassword123",
"newPassword": "newpassword456"
}'
New password (minimum 8 characters)
{
"message" : "Password changed successfully"
}
Update Profile
curl -X PATCH http://localhost:3001/api/auth/profile \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
-H "Content-Type: application/json" \
-d '{
"name": "Jane Doe"
}'
Updated display name (max 100 characters, whitespace trimmed)
{
"id" : "550e8400-e29b-41d4-a716-446655440000" ,
"email" : "user@example.com" ,
"name" : "Jane Doe" ,
"profileImage" : null ,
"isAdmin" : false ,
"status" : "active" ,
"createdAt" : "2026-03-02T10:30:00.000Z" ,
"updatedAt" : "2026-03-02T11:00:00.000Z"
}
Profile Image
Upload Profile Image
curl -X POST http://localhost:3001/api/auth/profile/image \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
-F "image=@/path/to/image.jpg"
Image file (JPEG, PNG, or WebP, max 5MB)
{
"profileImage" : "/uploads/profiles/550e8400-1234-5678-9abc-def012345678.jpg"
}
Delete Profile Image
curl -X DELETE http://localhost:3001/api/auth/profile/image \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
{
"message" : "Profile image removed successfully"
}
OIDC Authentication
Get OIDC Configuration
GET /api/auth/oidc/config
Get public OIDC configuration. Used by clients to check if OIDC is enabled and get provider information.
Authentication: None (public endpoint)
curl -X GET http://localhost:3001/api/auth/oidc/config
{
"enabled" : true ,
"providerName" : "Pocket ID" ,
"disableInternalAuth" : false
}
Initiate OIDC Login
GET /api/auth/oidc/initiate
Initiates the OIDC login flow by redirecting to the identity provider’s authorization URL.
Authentication: None (public endpoint)
Optional redirect URL after successful authentication
curl -X GET "http://localhost:3001/api/auth/oidc/initiate?redirect=/dashboard"
HTTP 302 Redirect to IdP authorization URL
This endpoint returns a redirect response to the OIDC provider’s authorization page.
OIDC Callback
GET /api/auth/oidc/callback
Handles the OIDC callback from the identity provider. This endpoint is called by the IdP after user authorization and redirects to the frontend with a one-time exchange code.
Authentication: None (public endpoint)
Authorization code from the IdP
State parameter for CSRF protection
Error code if authentication failed
Human-readable error description
This endpoint is configured as the callback URL in your OIDC provider: {APP_URL}/api/auth/oidc/callback
HTTP 302 Redirect to frontend:
- Success: /login?code={exchange_code}&redirect={redirect_url}
- Error: /login?error={error_message}
Exchange Code for Tokens
POST /api/auth/oidc/exchange
Exchange a one-time code (received from the callback) for access tokens and user information.
Authentication: None (public endpoint)
One-time exchange code from the callback redirect
curl -X POST http://localhost:3001/api/auth/oidc/exchange \
-H "Content-Type: application/json" \
-d '{
"code": "exchange-code-from-callback"
}'
{
"accessToken" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." ,
"refreshToken" : "refresh-token-uuid" ,
"user" : {
"id" : "user-uuid" ,
"email" : "user@example.com" ,
"name" : "John Doe" ,
"profileImage" : "https://example.com/avatar.jpg" ,
"isAdmin" : false ,
"status" : "active" ,
"createdAt" : "2026-03-01T10:00:00Z" ,
"updatedAt" : "2026-03-01T10:00:00Z"
}
}
Exchange Mobile Token
POST /api/auth/oidc/exchange/mobile
Exchange a mobile IdP access token for Anchor access tokens. Used by the mobile app for OIDC authentication.
Authentication: None (public endpoint)
Access token from the IdP (obtained via AppAuth/flutter_appauth)
curl -X POST http://localhost:3001/api/auth/oidc/exchange/mobile \
-H "Content-Type: application/json" \
-d '{
"access_token": "idp-access-token-from-mobile-app"
}'
{
"accessToken" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." ,
"refreshToken" : "refresh-token-uuid" ,
"user" : {
"id" : "user-uuid" ,
"email" : "user@example.com" ,
"name" : "John Doe" ,
"profileImage" : null ,
"isAdmin" : false ,
"status" : "active" ,
"createdAt" : "2026-03-01T10:00:00Z" ,
"updatedAt" : "2026-03-01T10:00:00Z"
}
}
The mobile OIDC flow requires configuring your OIDC provider as a public client (PKCE) with the redirect URI: anchor://oidc/callback