OAuth2/OIDC Setup Guide¶
Overview¶
This guide shows how to configure Cesivi Server to use OAuth2/OpenID Connect authentication with popular identity providers.
What You'll Learn: - How OAuth2/OIDC authentication works - Step-by-step setup for Azure AD, Okta, Auth0, Keycloak - Testing with dev-oidc (local development) - Troubleshooting common issues
How OAuth2/OIDC Works¶
┌──────────┐ ┌──────────────┐
│ Client │ │ Identity │
│ App │ │ Provider │
│ │ │ (Azure AD, │
│ │ │ Okta, etc.) │
└─────┬────┘ └──────┬───────┘
│ │
│ 1. Request token │
│────────────────────────────────────────────>│
│ │
│ 2. Validate credentials, issue JWT token │
│<────────────────────────────────────────────│
│ │
│ │
┌─────▼────┐ │
│ Bearer │ │
│ Token │ │
│ (JWT) │ │
└─────┬────┘ │
│ │
│ 3. API Request with Bearer token │
│────────────────────────────────────>┌───────▼───────┐
│ │ SharePoint │
│ │ Mock Server │
│ │ │
│ │ 4. Validate │
│ │ token: │
│ │ - Signature│
│ │ - Issuer │
│ │ - Audience │
│ │ - Lifetime │
│ 5. Response │ │
│<─────────────────────────────────────┤ │
│ └───────────────┘
Key Concepts: - JWT (JSON Web Token): Self-contained token with claims - Issuer: Identity provider that created the token - Audience: Intended recipient (Cesivi Server) - Claims: User information (username, email, groups, roles)
Azure AD / Entra ID Setup¶
Step 1: Register Application in Azure Portal¶
- Go to Azure Portal → Azure Active Directory → App registrations
- Click New registration
- Name:
Cesivi Server - Supported account types: Choose based on your needs
- Single tenant: Your organization only
- Multi-tenant: Any Azure AD tenant
- Redirect URI: Not needed for API-only app
- Click Register
Step 2: Create Client Secret (for confidential clients)¶
- Go to Certificates & secrets
- Click New client secret
- Description:
Cesivi Client - Expires: Choose appropriate lifetime
- Click Add
- Copy the secret value immediately (won't be shown again)
Step 3: Configure API Permissions (optional)¶
- Go to API permissions
- Click Add a permission
- Choose Microsoft Graph or custom APIs
- Select permissions needed
Step 4: Expose an API¶
- Go to Expose an API
- Click Add a scope
- Application ID URI: Accept default or customize (e.g.,
api://cesivi) - Scope name:
user_impersonation - Who can consent: Admins and users
- Admin consent display name: Access Cesivi Server
- Admin consent description: Allow the application to access Cesivi Server on your behalf
- Click Add scope
Step 5: Configure Cesivi Server¶
Update appsettings.json:
{
"Cesivi": {
"Identity": {
"Providers": {
"OAuth2": {
"Enabled": true,
"Priority": 50,
"Authority": "https://login.microsoftonline.com/{YOUR-TENANT-ID}/v2.0",
"Audience": "api://cesivi",
"ValidateIssuer": true,
"ValidateAudience": true,
"ValidateLifetime": true,
"ValidIssuers": [
"https://login.microsoftonline.com/{YOUR-TENANT-ID}/v2.0",
"https://sts.windows.net/{YOUR-TENANT-ID}/"
],
"ClaimMappings": {
"Username": "preferred_username",
"Email": "email",
"DisplayName": "name"
}
}
}
}
}
}
Replace:
- {YOUR-TENANT-ID} with your Azure AD tenant ID (from app overview)
Step 6: Get a Token¶
Using Client Credentials Flow¶
curl -X POST \
"https://login.microsoftonline.com/{YOUR-TENANT-ID}/oauth2/v2.0/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id={YOUR-CLIENT-ID}" \
-d "client_secret={YOUR-CLIENT-SECRET}" \
-d "scope=api://cesivi/.default" \
-d "grant_type=client_credentials"
Using Authorization Code Flow (interactive)¶
See Microsoft Identity Platform documentation
Step 7: Test Authentication¶
# Use the access_token from previous step
curl http://localhost:5000/_api/web \
-H "Authorization: Bearer {ACCESS_TOKEN}" \
-H "Accept: application/json"
Okta Setup¶
Step 1: Create Application in Okta Admin Console¶
- Go to Applications → Applications
- Click Create App Integration
- Sign-in method: API Services (for service-to-service)
- Or OIDC - OpenID Connect (for user authentication)
- Application type: Web Application (if using OIDC)
- Click Next
Step 2: Configure Application¶
- App integration name:
Cesivi Server - Grant type:
- Client Credentials (service-to-service)
- Authorization Code (user authentication)
- Controlled access: Choose who can access
- Click Save
Step 3: Note Credentials¶
From the application page, copy:
- Client ID
- Client Secret
- Okta domain (e.g., https://dev-12345.okta.com)
Step 4: Configure Cesivi Server¶
{
"Cesivi": {
"Identity": {
"Providers": {
"OAuth2": {
"Enabled": true,
"Priority": 50,
"Authority": "https://{YOUR-OKTA-DOMAIN}/oauth2/default",
"Audience": "api://default",
"ValidateIssuer": true,
"ValidateAudience": true,
"ValidateLifetime": true,
"ClaimMappings": {
"Username": "sub",
"Email": "email",
"DisplayName": "name"
}
}
}
}
}
}
Replace:
- {YOUR-OKTA-DOMAIN} with your Okta domain
Step 5: Get a Token¶
curl -X POST \
"https://{YOUR-OKTA-DOMAIN}/oauth2/default/v1/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id={YOUR-CLIENT-ID}" \
-d "client_secret={YOUR-CLIENT-SECRET}" \
-d "grant_type=client_credentials" \
-d "scope=sharepoint_mock"
Auth0 Setup¶
Step 1: Create API in Auth0 Dashboard¶
- Go to Applications → APIs
- Click Create API
- Name:
Cesivi Server API - Identifier:
https://cesivi-api(this becomes your audience) - Signing Algorithm: RS256
- Click Create
Step 2: Create Application¶
- Go to Applications → Applications
- Click Create Application
- Name:
Cesivi Client - Application Type: Machine to Machine Applications
- Authorize: Select your API (Cesivi Server API)
- Permissions: Select scopes needed
- Click Authorize
Step 3: Note Credentials¶
From the application settings:
- Domain (e.g., dev-xyz.us.auth0.com)
- Client ID
- Client Secret
Step 4: Configure Cesivi Server¶
{
"Cesivi": {
"Identity": {
"Providers": {
"OAuth2": {
"Enabled": true,
"Priority": 50,
"Authority": "https://{YOUR-AUTH0-DOMAIN}/",
"Audience": "https://cesivi-api",
"ValidateIssuer": true,
"ValidateAudience": true,
"ValidateLifetime": true,
"ClaimMappings": {
"Username": "sub",
"Email": "email",
"DisplayName": "name"
}
}
}
}
}
}
Replace:
- {YOUR-AUTH0-DOMAIN} with your Auth0 domain
Step 5: Get a Token¶
curl -X POST \
"https://{YOUR-AUTH0-DOMAIN}/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id={YOUR-CLIENT-ID}" \
-d "client_secret={YOUR-CLIENT-SECRET}" \
-d "audience=https://cesivi-api" \
-d "grant_type=client_credentials"
Keycloak Setup¶
Step 1: Create Realm¶
- Go to Keycloak Admin Console
- Hover over realm dropdown → Add realm
- Name:
cesivi - Click Create
Step 2: Create Client¶
- Go to Clients → Create
- Client ID:
cesivi-server - Client Protocol: openid-connect
- Click Save
Step 3: Configure Client¶
- Access Type: confidential
- Service Accounts Enabled: ON
- Authorization Enabled: ON (optional)
- Valid Redirect URIs:
http://localhost:5000/* - Click Save
Step 4: Note Credentials¶
Go to Credentials tab: - Copy Secret
Step 5: Configure Cesivi Server¶
{
"Cesivi": {
"Identity": {
"Providers": {
"OAuth2": {
"Enabled": true,
"Priority": 50,
"Authority": "https://{KEYCLOAK-HOST}/realms/cesivi",
"Audience": "cesivi-server",
"ValidateIssuer": true,
"ValidateAudience": true,
"ValidateLifetime": true,
"ClaimMappings": {
"Username": "preferred_username",
"Email": "email",
"DisplayName": "name"
}
}
}
}
}
}
Replace:
- {KEYCLOAK-HOST} with your Keycloak server URL
Step 6: Get a Token¶
curl -X POST \
"https://{KEYCLOAK-HOST}/realms/cesivi/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=cesivi-server" \
-d "client_secret={YOUR-CLIENT-SECRET}" \
-d "grant_type=client_credentials"
Local Development with dev-oidc¶
For local development without external identity providers, use dev-oidc (zero-configuration OIDC server).
Step 1: Start dev-oidc¶
cd C:\Source\_AI\dev-oidc
.\dev-oidc.exe
# Server starts on http://localhost:8080
Step 2: Configure Cesivi Server¶
{
"Cesivi": {
"Identity": {
"Providers": {
"OAuth2": {
"Enabled": true,
"Priority": 50,
"Authority": "http://localhost:8080",
"Audience": "cesivi",
"ValidateIssuer": true,
"ValidateAudience": true,
"ValidateLifetime": true,
"RequireHttpsMetadata": false,
"ClaimMappings": {
"Username": "preferred_username",
"Email": "email",
"DisplayName": "name"
}
}
}
}
}
}
Note: RequireHttpsMetadata: false allows HTTP for local development
Step 3: Get a Token¶
# Any credentials work with dev-oidc
curl -X POST http://localhost:8080/token \
-d "grant_type=client_credentials" \
-d "client_id=cesivi" \
-d "client_secret=any-secret"
Claim Mappings¶
Claims are pieces of information about the user in the JWT token. Different identity providers use different claim names.
Default Mappings¶
{
"ClaimMappings": {
"Username": "preferred_username",
"Email": "email",
"DisplayName": "name"
}
}
Common Claim Names by Provider¶
| Provider | Username | Display Name | Groups/Roles | |
|---|---|---|---|---|
| Azure AD | preferred_username |
email |
name |
groups, roles |
| Okta | sub |
email |
name |
groups |
| Auth0 | sub |
email |
name |
Custom namespace |
| Keycloak | preferred_username |
email |
name |
realm_access.roles |
Custom Claim Mappings¶
If your identity provider uses different claim names:
{
"ClaimMappings": {
"Username": "custom_username_claim",
"Email": "custom_email_claim",
"DisplayName": "custom_name_claim",
"Groups": "custom_groups_claim",
"Roles": "custom_roles_claim"
}
}
Troubleshooting¶
"Token validation failed: Invalid signature"¶
Cause: Token signature doesn't match public key from JWKS endpoint
Solutions:
1. Check Authority URL is correct
2. Verify OIDC discovery endpoint is accessible: {Authority}/.well-known/openid-configuration
3. Check JWKS endpoint is accessible
4. Verify token is from correct issuer
# Test OIDC discovery
curl https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration
"Token validation failed: Invalid issuer"¶
Cause: Token issuer doesn't match configured valid issuers
Solutions:
1. Check ValidIssuers array in configuration
2. Azure AD might use two issuer formats - add both:
"ValidIssuers": [
"https://login.microsoftonline.com/{tenant-id}/v2.0",
"https://sts.windows.net/{tenant-id}/"
]
"Token validation failed: Invalid audience"¶
Cause: Token audience doesn't match configured audience
Solutions:
1. Check Audience in configuration matches aud claim in token
2. For Azure AD, audience should be your Application ID URI
3. Decode token at jwt.ms to see actual aud claim
"Token validation failed: Token expired"¶
Cause: Token lifetime exceeded
Solutions:
1. Get a new token
2. Adjust ClockSkew if time synchronization issues:
{
"OAuth2": {
"ClockSkew": "00:10:00"
}
}
"Could not retrieve OIDC configuration"¶
Cause: Cannot access OIDC discovery endpoint
Solutions: 1. Check network connectivity 2. Verify Authority URL is correct 3. Check firewall/proxy settings 4. For HTTPS, verify SSL certificate is valid
Enable Debug Logging¶
Add to appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Cesivi.Common.Identity": "Debug"
}
}
}
This will log: - JWT validation steps - OIDC discovery requests - Claim mapping results - Authentication failures with details
Security Best Practices¶
Production Checklist¶
- [ ] Use HTTPS for all communications
- [ ] Set
RequireHttpsMetadata: true - [ ] Use strong client secrets (if applicable)
- [ ] Rotate signing keys regularly
- [ ] Set appropriate token lifetimes (not too long)
- [ ] Validate all required claims (issuer, audience, lifetime)
- [ ] Store secrets in secure configuration (Azure Key Vault, AWS Secrets Manager)
- [ ] Enable logging for security audit trail
- [ ] Monitor for authentication failures
- [ ] Keep JWT libraries up to date
Token Lifetime Recommendations¶
| Scenario | Access Token | Refresh Token |
|---|---|---|
| Web App | 1-5 minutes | 7-30 days |
| SPA | 5-15 minutes | N/A (use silent renewal) |
| Mobile App | 15-60 minutes | 30-90 days |
| Service-to-Service | 1-24 hours | N/A |
See Also¶
- Identity Providers Overview - Choose authentication method
- NTLM Setup Guide - Windows/Enterprise authentication
- API Reference - Authentication endpoints
- Troubleshooting Guide - Common issues