Skip to content

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

  1. Go to Azure PortalAzure Active DirectoryApp registrations
  2. Click New registration
  3. Name: Cesivi Server
  4. Supported account types: Choose based on your needs
  5. Single tenant: Your organization only
  6. Multi-tenant: Any Azure AD tenant
  7. Redirect URI: Not needed for API-only app
  8. Click Register

Step 2: Create Client Secret (for confidential clients)

  1. Go to Certificates & secrets
  2. Click New client secret
  3. Description: Cesivi Client
  4. Expires: Choose appropriate lifetime
  5. Click Add
  6. Copy the secret value immediately (won't be shown again)

Step 3: Configure API Permissions (optional)

  1. Go to API permissions
  2. Click Add a permission
  3. Choose Microsoft Graph or custom APIs
  4. Select permissions needed

Step 4: Expose an API

  1. Go to Expose an API
  2. Click Add a scope
  3. Application ID URI: Accept default or customize (e.g., api://cesivi)
  4. Scope name: user_impersonation
  5. Who can consent: Admins and users
  6. Admin consent display name: Access Cesivi Server
  7. Admin consent description: Allow the application to access Cesivi Server on your behalf
  8. 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

  1. Go to ApplicationsApplications
  2. Click Create App Integration
  3. Sign-in method: API Services (for service-to-service)
  4. Or OIDC - OpenID Connect (for user authentication)
  5. Application type: Web Application (if using OIDC)
  6. Click Next

Step 2: Configure Application

  1. App integration name: Cesivi Server
  2. Grant type:
  3. Client Credentials (service-to-service)
  4. Authorization Code (user authentication)
  5. Controlled access: Choose who can access
  6. 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

  1. Go to ApplicationsAPIs
  2. Click Create API
  3. Name: Cesivi Server API
  4. Identifier: https://cesivi-api (this becomes your audience)
  5. Signing Algorithm: RS256
  6. Click Create

Step 2: Create Application

  1. Go to ApplicationsApplications
  2. Click Create Application
  3. Name: Cesivi Client
  4. Application Type: Machine to Machine Applications
  5. Authorize: Select your API (Cesivi Server API)
  6. Permissions: Select scopes needed
  7. 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

  1. Go to Keycloak Admin Console
  2. Hover over realm dropdown → Add realm
  3. Name: cesivi
  4. Click Create

Step 2: Create Client

  1. Go to ClientsCreate
  2. Client ID: cesivi-server
  3. Client Protocol: openid-connect
  4. Click Save

Step 3: Configure Client

  1. Access Type: confidential
  2. Service Accounts Enabled: ON
  3. Authorization Enabled: ON (optional)
  4. Valid Redirect URIs: http://localhost:5000/*
  5. 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 Email 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


External Resources