Legal

OAuth 2.0 & OpenID Connect SSO

Complete guide to integrating OpenID Connect single sign-on with Advanza.

Last updated: August 26, 2026

Overview

Advanza is a multitenant SaaS marketing platform that supports OpenID Connect (OIDC) and OAuth 2.0 for secure authentication and single sign-on (SSO). This guide covers supported flows, endpoints, scopes, and best practices for integrating Advanza authentication into your applications.

Protocol: OpenID Connect 1.0 (built on OAuth 2.0 Authorization Code Grant)
Provider: Advanza (via OpenIddict 5.x)
Multi-Tenancy: Full support – each organization is a separate tenant
Security: HTTPS required, PKCE recommended for SPAs, certificates for confidential clients

Supported Authentication Flows

Authorization Code Flow (Recommended)

The OAuth 2.0 Authorization Code Flow is the recommended and most secure flow for most applications, including web apps and single-page applications (SPAs). It uses PKCE (Proof Key for Code Exchange) for public clients to prevent authorization code interception attacks.

Best for: Web applications, SPAs, mobile apps, third-party integrations

Refresh Token Flow

Use refresh tokens to obtain new access tokens without requiring the user to sign in again. Refresh tokens are valid for 14 days and can be rotated to maintain security.

Best for: Long-lived sessions, background services, offline access

Client Credentials Flow (Legacy)

The OAuth 2.0 Resource Owner Password Credentials flow is supported for backward compatibility with legacy integrations. New integrations should use the Authorization Code Flow instead.

Best for: Legacy applications, internal tools (not recommended for new development)

API Endpoints

All endpoints are hosted at https://api.advanza.ai

Authorization Endpoint

GET /connect/authorize

Initiates the OAuth authorization flow. Redirects user to sign in with their identity provider (Microsoft, Google, or email/password).

Query Parameters:

  • client_id (required): Your application ID
  • redirect_uri (required): URL to redirect after authentication
  • response_type (required): Must be 'code'
  • scope (required): Space-separated list of scopes (openid, email, profile, offline_access, roles)
  • code_challenge (required for SPA): PKCE code challenge
  • code_challenge_method (required with code_challenge): 'S256'
  • state (recommended): Random string to prevent CSRF attacks
  • tenant_id (optional): Specific tenant to authenticate into

Token Endpoint

POST /connect/token

Exchanges an authorization code for access tokens, ID token, and optional refresh token.

Request Format: application/x-www-form-urlencoded

Parameters:

  • grant_type (required): 'authorization_code', 'refresh_token', or 'password'
  • code (required for auth code flow): Authorization code from /authorize
  • client_id (required): Your application ID
  • client_secret (required): Your application secret (keep confidential)
  • redirect_uri (required): Must match the /authorize request
  • code_verifier (required for SPA): PKCE code verifier
  • refresh_token (for refresh flow): The refresh token to exchange
  • username & password (for password flow): User credentials

Token Introspection Endpoint

POST /connect/introspect

Validates and inspects the contents of an access token or refresh token.

OpenID Configuration

GET /.well-known/openid-configuration

Standard OIDC metadata endpoint. Returns discovery information including endpoints, public keys, supported scopes, and grant types.

Scopes

Request scopes via the scope parameter on the authorization request:

openid (required)

Requests an ID token containing the user's identity information (subject claim, name, tenant ID, etc.)

email

Requests user email address and email verification status

profile

Requests user profile information: name, given_name, family_name

offline_access

Requests a refresh token to extend access without requiring re-authentication

roles

Requests the user's roles/permissions (e.g., "Owner", "Editor", "Viewer")

Minimum scope for login: openid email profile

Example: Authorization Code Flow with PKCE

This example demonstrates the recommended flow for single-page applications (SPAs) and mobile apps.

Step 1: Generate PKCE Challenge

Create a code verifier and challenge on the client side:

// 1. Generate random code verifier (43-128 characters)
const codeVerifier = generateRandomString(128);

// 2. Create code challenge via SHA256 hash
const codeChallenge = await crypto.subtle.digest('SHA-256',
  new TextEncoder().encode(codeVerifier)
);

// 3. Base64-URL encode the challenge
const codeChallengeB64 = base64UrlEncode(codeChallenge);

// Store codeVerifier in sessionStorage for Step 3
sessionStorage.setItem('pkce_verifier', codeVerifier);

Step 2: Redirect to Authorization Endpoint

Direct the user to sign in:

GET /connect/authorize?
  client_id={your_app_id}
  &redirect_uri=https://your-app.com/callback
  &response_type=code
  &scope=openid email profile
  &code_challenge={pkce_challenge}
  &state={random_state}

The user will be redirected to their identity provider (Microsoft, Google, or email/password), complete authentication, and be redirected back to your redirect_uri with an authorization code.

Step 3: Exchange Code for Tokens

From your backend, exchange the authorization code:

POST /connect/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code={auth_code}
&client_id={your_app_id}
&client_secret={your_app_secret}
&redirect_uri=https://your-app.com/callback
&code_verifier={pkce_verifier}

Step 4: Token Response

On success, you receive:

{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "DefxA1234567890...",
  "id_token": "eyJhbGciOiJSUzI1NiIs..."
}

Step 5: Verify ID Token

Validate the ID token signature using the public key from /.well-known/openid-configuration, verify the issuer and audience claims, and extract user information.

Token Claims

ID Token Claims

The ID token (JWT) contains user identity information:

{
  "sub": "550e8400-e29b-41d4-a716-446655440000",
  "email": "user@company.com",
  "email_verified": true,
  "name": "John Doe",
  "given_name": "John",
  "family_name": "Doe",
  "tenant_id": "12345678-1234-1234-1234-123456789012",
  "iss": "https://api.advanza.ai",
  "aud": "your_app_id",
  "iat": 1234567890,
  "exp": 1234571490
}

Key Claims:

  • sub: Unique user identifier (Guid)
  • email: User's email address
  • email_verified: Whether email is verified
  • name, given_name, family_name: User's name
  • tenant_id: User's active tenant/organization
  • iss: Token issuer (always https://api.advanza.ai)
  • aud: Intended audience (your application ID)
  • iat: Token issued at (Unix timestamp)
  • exp: Token expiration (Unix timestamp)

Access Token Claims

The access token (JWT) contains authorization information:

{
  "sub": "550e8400-e29b-41d4-a716-446655440000",
  "email": "user@company.com",
  "name": "John Doe",
  "tenant_id": "12345678-1234-1234-1234-123456789012",
  "roles": ["Owner"],
  "scope": "openid email profile offline_access roles",
  "iss": "https://api.advanza.ai",
  "aud": "your_app_id",
  "iat": 1234567890,
  "exp": 1234571490
}

Key Claims:

  • sub: User ID
  • email, name: User information
  • tenant_id: Active tenant (use for multi-tenancy routing)
  • roles: User's roles in the tenant
  • scope: Granted scopes
  • exp: Expiration (typically 1 hour)

Use Access Token For: Include in Authorization header (Authorization: Bearer {access_token}) when calling Advanza APIs or your backend.

Multi-Tenancy

Advanza is a multitenant platform. Each user can be a member of multiple organizations (tenants). The tenant_id claim in both ID and access tokens indicates the user's active tenant context.

Default Tenant

On first sign-in, the user is assigned a default tenant. The tenant_id claim will be populated with this tenant's ID.

Switching Tenants

Users with multiple tenant memberships can switch tenants by passing the desired tenant_id parameter to the authorization endpoint:

GET /connect/authorize?
  client_id={your_app_id}
  &redirect_uri=https://your-app.com/callback
  &response_type=code
  &scope=openid email profile
  &tenant_id=12345678-1234-1234-1234-123456789012
  &code_challenge={pkce_challenge}

Routing by Tenant

Use the tenant_id claim to route requests to the correct tenant context in your backend:

// Extract tenant from token claims
const tenantId = tokenClaims.tenant_id;

// Route request to tenant context
const tenantContext = getTenantContext(tenantId);
const result = await performAction(tenantContext, action);

Security Best Practices

Use HTTPS in Production

All OAuth requests must use HTTPS to protect credentials and tokens.

PKCE for SPAs and Mobile Apps

Always use PKCE (Proof Key for Code Exchange) for public clients. This prevents authorization code interception attacks.

Keep Client Secret Confidential

Never expose your client secret in client-side code, logs, or version control. Only use it in secure backend-to-backend communication.

Validate State Parameter

Always generate and validate the state parameter to prevent CSRF attacks.

Verify Token Signatures

Always validate ID token and access token signatures using the public key from the OIDC configuration endpoint before trusting their contents.

Refresh Tokens Securely

Store refresh tokens securely (HttpOnly cookies or secure storage, not localStorage). Set appropriate expiration times.

Handle Token Expiration

Access tokens expire after 60 minutes. Implement token refresh logic to maintain uninterrupted access.

Support

For questions, issues, or integration assistance, please contact our support team:

Email: support@advanza.ai
Documentation: https://advanza.ai/docs
Status: https://status.advanza.ai