IDP Support Center
  • Welcome
  • Getting started
    • What is IDP?
  • User Guide
    • User guide center
    • Get started with OXU
      • OXU Identity user guide
    • Account Management
      • Authentication
        • Sign up with Email and Password
        • Sign up with Google (optional)
        • Sign in with Email and Password
        • Google OIDC: Sign in to Google via OXU
        • Password requirements enforcement
        • Secure password hashing and storage
      • Account security
        • What should I do if I don't receive a verification code when signing up or forgot password?
        • Email verification
        • Two-Factor Authentication
          • Passkey authentication
          • 2FA-Email verification codes
          • MFA-Authenticator apps (TOTP)
          • MFA-Passkeys (FIDO2 / WebAuthn)
      • Data & Privacy
      • User Experience
        • Cross-platform web support
      • App Consent Management
    • Organization Admin App
      • Business Owner (Default Authority)
        • Organization Management
          • Organization creation
          • Domain ownership verification (DNS)
        • Organizational Structure
          • Organizational Units (OUs)
          • Workspaces
          • Hierarchical access scoping
        • Security & Governance
          • Enforced security policies
            • IP-Based access control
            • Geo-based access policies
            • Device and platform restrictions
          • Enforcing stronger authentication for risky login behavior
            • Risk Detection signals
            • Step-Up authentication
        • Roles & permissions
          • Assign role to user in Organization
          • Permissions list
      • SCIM – Automated user and workspace provisioning
        • What is SCIM used for?
        • User Lifecycle management
      • Administrator
        • Team & Access
          • Invite and manage users
          • Assign roles
          • Manage access at OU and Workspace level
            • Manage Access at Organizational Unit (OU)
            • Manage Workspace level
              • Team & Access – Members Management
        • Group management
        • Organization Unit
          • Create & manage Organization Units
          • Viewing and searching Organizational Units
          • Moving an Organizational Unit
          • Deleting an Organizational Unit
        • Manage activity logs of Organization's member
      • Become an OXU developer
      • App management - Workspace access
      • Report & Analytics Center
    • OXU Workspace
      • Guide to create workspace
      • Guide to manage workspace information
      • Guide to manage role and permissions
      • Applications
        • Guide to manage applications
        • OXU Developer
          • What is OXU developer
          • User guides
            • 1. Become OXU developer
            • 2. Create an app
            • 3. Input application info
              • About app ratings and reviews
            • 4. Config resource & security info
            • Security Best Practices
            • 5. Set up Pricing info
            • 6. Publish your app
              • Prepare before publishing your app
            • 7. Manage your app
              • App lifecycle
          • App versioning
        • OXU Store
          • What is OXU Store
          • 1. Register as an user
          • 2. Browsing & searching apps
          • 3. View app details
          • 4. Subscribe an app
            • Enable & Subscribe app for business workspace
          • 5. Manage subscriptions
          • 6. Rate & review an app
  • Support
    • Support center
      • What is Oten account & what can I do with Account Management App?
      • How to create account and password?
      • How to manage your Oten account information?
      • How to use MFA to protect your account?
      • What is WorkSpace & what can you do with WS?
      • What is Organization Admin app & what can you do with OAA?
    • Privacy Policy
    • Terms and conditions
      • Oten developer terms and conditions
      • Oten Store terms and conditions
    • FAQs
      • Store FAQs
      • Developer FAQ
    • Contact Us
  • Integration
    • Integration document
      • IDP integration
        • Environments: sandbox & production
        • Regular web application client
        • Native application client
        • Single page application client
        • SAML integration
        • Managing your integration applications
        • FAQ
      • What is SSO?
      • Why use SSO?
    • Provisioning connector
      • Google Workspace Configuration
    • Understand SSO flow
      • Overview
      • Flow Diagram
    • Developer Integration guide
      • Integration flow overview
    • Oten to OXU Migration guide
    • Prerequisites
      • Discovery Configuration
      • JAR Requirement - CRITICAL
      • JAR Complete Implementation Guide
      • PKCE Implementation Guide
        • Step 1: Choose OAuth Library
        • Step 2: Configure OAuth Client
        • Step 3: Implement Authorization Flow
        • Step 4: Handle Callback
        • Step 5: Token Management
      • Best practice
        • Security
      • Support & Troubleshoot
        • Common Errors
        • Debug and Troubleshooting
        • Contact Support
      • Appendix
        • Configuration Reference
        • Error Codes Reference
        • API Reference
        • Sample Code
        • Glossary
  • What's New
    • v1.0.29 - Aug 19, 2026
    • v1.0.28 - Aug 12, 2026
    • v1.0.27 - Aug 08, 2026
    • v1.0.26 - July 29 & 31, 2026
    • v1.0.25 - July 22, 2026
    • v1.0.24 - Jun 21, 2026
    • v1.0.23 - Jun 17, 2026
    • v1.0.22 - Jun 03, 2026
    • v1.0.21 - May 27, 2026
    • v1.0.20 - Apr 28, 2026
    • v1.0.19 - Apr 21, 2026
    • v1.0.18 - Apr 15, 2026
    • v1.0.17 - Apr 03, 2026
    • v1.0.16 - Mar 28, 2026
    • v1.0.15 - Mar 05 & 13, 2026
    • v1.0.14 - Feb 11, 2026
    • v1.0.13 - Jan 14, 2026
    • v1.0.12 - Jan 05, 2026
    • v1.0.11 - Jan 04, 2026
    • v1.0.10 - Dec 25, 2025
    • v1.0.9 - Dec 07, 2025
    • v1.0.8 - Nov 23, 2025
    • v1.0.7 - Nov 09, 2025
    • v1.0.6 - Oct 26, 2025
    • v1.0.5 - Sep 29, 2025
    • v1.0.4 - Sep 28, 2025
    • v1.0.3 - Sep 14, 2025
    • v1.0.2 - Aug 31, 2025
    • v1.0.1 - Aug 17, 2025
    • v1.0.0 - Aug 03, 2025
On this page
  1. Integration
  2. Prerequisites
  3. PKCE Implementation Guide

Step 2: Configure OAuth Client

PreviousStep 1: Choose OAuth LibraryNextStep 3: Implement Authorization Flow

Last updated 9 months ago

  • What You'll Learn
  • Configuration Methods
  • Method 1: Discovery Configuration (Recommended)
  • Method 2: Manual Configuration
  • Oten IDP Endpoints
  • Primary Endpoints
  • Discovery Endpoint Usage
  • Environment Variables Setup
  • Create Environment File
  • Load Environment Variables
  • Technology-Specific Configurations
  • Node.js with openid-client
  • Python with Authlib
  • Java Spring Boot
  • C# ASP.NET Core
  • 🔒 Client Types and Security
  • Confidential Clients (Server-Side)
  • Public Clients (Client-Side)
  • 🎯 Scope Configuration
  • Standard Scopes
  • Dynamic Scope Selection
  • Advanced Configuration Options
  • Timeout Settings
  • Custom Headers
  • 🧪 Testing Your Configuration
  • Configuration Validation
  • Test Authorization URL Generation
  • 🔍 Configuration Troubleshooting
  • Common Issues
  • Debug Configuration
  • Configuration Checklist
  • Navigation

Now that you've chosen your OAuth library, it's time to configure your OAuth client with Oten IDP endpoints and credentials.

Need context? Check the Integration Flow Overview to see how this step fits into the complete process.

What You'll Learn

In this step, you will:

  • Set up OAuth client configuration using Discovery (recommended)

  • Configure Oten IDP endpoints automatically or manually

  • Understand different client types and their configurations

  • Set up environment variables securely

  • Test your basic configuration

Configuration Methods

Method 1: Discovery Configuration (Recommended)

Use OpenID Connect Discovery to automatically fetch configuration:

📖 Detailed Guide: See Discovery Configuration for complete implementation examples.

// Automatic configuration using discovery
async function createOAuthConfig() {
  const discoveryUrl = 'https://account.oten.com/.well-known/openid-configuration';
  const response = await fetch(discoveryUrl);
  const 

If you prefer to configure endpoints manually:

Many libraries support automatic configuration via the discovery endpoint:

Create a .env file (never commit to version control):

For applications that can securely store secrets:

For SPAs, mobile apps, and other clients that cannot store secrets:

Before proceeding to the next step, ensure:


Progress: Step 2 of 5 complete ✅

Method 2: Manual Configuration

const oauthConfig = {
  // Client credentials (from Oten registration)
  clientId: 'your-client-id',
  clientSecret: 'your-client-secret', // Only for confidential clients

  // Oten IDP endpoints (manual)
  authorizationURL: 'https://account.oten.com/v1/oauth/authorize',
  tokenURL: 'https://account.oten.com/v1/oauth/token',
  userInfoURL: 'https://account.oten.com/v1/oauth/userinfo',

  // Application settings
  redirectURI: 'https://yourapp.com/callback',
  scopes: ['openid', 'profile', 'email'],

  // OAuth flow settings
  responseType: 'code',
  grantType: 'authorization_code'
};

Oten IDP Endpoints

Primary Endpoints

const otenEndpoints = {
  // Authorization endpoint - where users are redirected to login
  authorization: 'https://account.oten.com/v1/oauth/authorize',

  // Token endpoint - where authorization codes are exchanged for tokens
  token: 'https://account.oten.com/v1/oauth/token',

  // UserInfo endpoint - where user information is retrieved
  userInfo: 'https://account.oten.com/v1/oauth/userinfo',

  // JWKS endpoint - for token signature verification
  jwks: 'https://account.oten.com/.well-known/jwks.json',

  // OpenID Connect discovery endpoint
  discovery: 'https://account.oten.com/.well-known/openid_configuration'
};

Discovery Endpoint Usage

// Automatic discovery (recommended)
const issuerUrl = 'https://account.oten.com';

// The library will automatically fetch:
// - Authorization endpoint
// - Token endpoint  
// - UserInfo endpoint
// - JWKS endpoint
// - Supported scopes and response types

Environment Variables Setup

Create Environment File

# Oten OAuth Configuration
OTEN_CLIENT_ID=your_client_id_here
OTEN_CLIENT_SECRET=your_client_secret_here
OTEN_REDIRECT_URI=https://yourapp.com/callback

# Oten Endpoints (optional if using discovery)
OTEN_ISSUER=https://account.oten.com
OTEN_AUTH_URL=https://account.oten.com/v1/oauth/authorize
OTEN_TOKEN_URL=https://account.oten.com/v1/oauth/token

# Application Settings
NODE_ENV=development
PORT=3000
SESSION_SECRET=your_session_secret_here

Load Environment Variables

// Load environment variables
require('dotenv').config();

const config = {
  clientId: process.env.OTEN_CLIENT_ID,
  clientSecret: process.env.OTEN_CLIENT_SECRET,
  redirectURI: process.env.OTEN_REDIRECT_URI,
  issuer: process.env.OTEN_ISSUER
};

// Validate required configuration
if (!config.clientId) {
  throw new Error('OTEN_CLIENT_ID is required');
}

if (!config.redirectURI) {
  throw new Error('OTEN_REDIRECT_URI is required');
}

Technology-Specific Configurations

Node.js with openid-client

const { Issuer } = require('openid-client');

async function setupOAuthClient() {
  // Discover Oten configuration
  const otenIssuer = await Issuer.discover('https://account.oten.com');

  // Create client
  const client = new otenIssuer.Client({
    client_id: process.env.OTEN_CLIENT_ID,
    client_secret: process.env.OTEN_CLIENT_SECRET,
    redirect_uris: [process.env.OTEN_REDIRECT_URI],
    response_types: ['code'],
    grant_types: ['authorization_code', 'refresh_token'],
    token_endpoint_auth_method: 'client_secret_basic'
  });
  
  return client;
}

Python with Authlib

from authlib.integrations.flask_client import OAuth
from flask import Flask

app = Flask(__name__)
app.secret_key = os.environ.get('SESSION_SECRET')

oauth = OAuth(app)

# Configure Oten OAuth
oten = oauth.register(
    name='oten',
    client_id=os.environ.get('OTEN_CLIENT_ID'),
    client_secret=os.environ.get('OTEN_CLIENT_SECRET'),
    server_metadata_url='https://account.oten.com/.well-known/openid_configuration',
    client_kwargs={
        'scope': 'openid profile email',
        'response_type': 'code',
        'grant_type': 'authorization_code'
    }
)

Java Spring Boot

# application.yml
spring:
  security:
    oauth2:
      client:
        registration:
          oten:
            client-id: ${OTEN_CLIENT_ID}
            client-secret: ${OTEN_CLIENT_SECRET}
            scope: openid,profile,email
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
            client-name: Oten
        provider:
          oten:
            issuer-uri: https://account.oten.com
            authorization-uri: https://account.oten.com/v1/oauth/authorize
            token-uri: https://account.oten.com/v1/oauth/token
            user-info-uri: https://account.oten.com/v1/oauth/userinfo
            jwk-set-uri: https://account.oten.com/.well-known/jwks.json
            user-name-attribute: sub

C# ASP.NET Core

// Startup.cs or Program.cs
services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
    options.LoginPath = "/Account/Login";
    options.LogoutPath = "/Account/Logout";
})
.AddOpenIdConnect(options =>
{
    options.Authority = "https://account.oten.com";
    options.ClientId = Configuration["Oten:ClientId"];
    options.ClientSecret = Configuration["Oten:ClientSecret"];
    options.ResponseType = "code";
    options.SaveTokens = true;
    
    options.Scope.Clear();
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Scope.Add("email");
    
    options.CallbackPath = "/signin-oidc";
    options.SignedOutCallbackPath = "/signout-callback-oidc";
    
    options.GetClaimsFromUserInfoEndpoint = true;
    options.ClaimActions.MapJsonKey("email", "email");
    options.ClaimActions.MapJsonKey("name", "name");
});

🔒 Client Types and Security

Confidential Clients (Server-Side)

const confidentialClientConfig = {
  clientId: process.env.OTEN_CLIENT_ID,
  clientSecret: process.env.OTEN_CLIENT_SECRET, // Secret is secure
  
  // Authentication method for token endpoint
  tokenEndpointAuthMethod: 'client_secret_basic', // or 'client_secret_post'
  
  // Grant types
  grantTypes: ['authorization_code', 'refresh_token'],
  
  // Response types
  responseTypes: ['code']
};

Public Clients (Client-Side)

const publicClientConfig = {
  clientId: process.env.OTEN_CLIENT_ID,
  // No client secret for public clients
  
  // PKCE is required for security
  usePKCE: true,
  
  // Authentication method
  tokenEndpointAuthMethod: 'none',
  
  // Grant types
  grantTypes: ['authorization_code', 'refresh_token'],
  
  // Response types
  responseTypes: ['code']
};

🎯 Scope Configuration

Standard Scopes

const scopes = {
  // Required for OpenID Connect
  openid: 'openid',
  
  // User profile information
  profile: 'profile', // name, given_name, family_name, etc.
  
  // Email information
  email: 'email', // email, email_verified
  
  // Additional scopes (if available)
  phone: 'phone', // phone_number, phone_number_verified
  address: 'address', // formatted address information
  
  // Custom Oten scopes
  workspace: 'workspace', // workspace information
  roles: 'roles' // user roles and permissions
};

// Combine scopes
const requestedScopes = ['openid', 'profile', 'email', 'workspace'];

Dynamic Scope Selection

function buildScopes(userType, features) {
  const baseScopes = ['openid', 'profile', 'email'];
  
  if (userType === 'admin') {
    baseScopes.push('roles', 'workspace');
  }
  
  if (features.includes('phone_verification')) {
    baseScopes.push('phone');
  }
  
  return baseScopes;
}

Advanced Configuration Options

Timeout Settings

const advancedConfig = {
  // HTTP timeouts
  timeout: 30000, // 30 seconds
  
  // Token refresh settings
  refreshTokenTolerance: 300, // Refresh 5 minutes before expiry
  
  // Clock skew tolerance
  clockTolerance: 60, // 1 minute tolerance for JWT validation
  
  // Retry settings
  retryAttempts: 3,
  retryDelay: 1000 // 1 second between retries
};

Custom Headers

const customConfig = {
  // Custom headers for all requests
  headers: {
    'User-Agent': 'MyApp/1.0.0',
    'X-Client-Version': '1.0.0'
  },
  
  // Custom parameters
  customParameters: {
    // Add custom parameters to authorization requests
    ui_locales: 'en-US',
    prompt: 'consent' // Force consent screen
  }
};

🧪 Testing Your Configuration

Configuration Validation

async function validateConfiguration() {
  try {
    // Test discovery endpoint
    const response = await fetch('https://account.oten.com/.well-known/openid_configuration');
    const config = await response.json();

    console.log('✅ Discovery endpoint accessible');
    console.log('Supported scopes:', config.scopes_supported);
    console.log('Supported response types:', config.response_types_supported);

    // Validate client configuration
    if (!process.env.OTEN_CLIENT_ID) {
      throw new Error('❌ Client ID not configured');
    }

    if (!process.env.OTEN_REDIRECT_URI) {
      throw new Error('❌ Redirect URI not configured');
    }
    
    console.log('✅ Client configuration valid');
    
  } catch (error) {
    console.error('❌ Configuration validation failed:', error.message);
    throw error;
  }
}

Test Authorization URL Generation

function testAuthorizationURL() {
  const authURL = new URL('https://account.oten.com/v1/oauth/authorize');

  authURL.searchParams.set('client_id', process.env.OTEN_CLIENT_ID);
  authURL.searchParams.set('redirect_uri', process.env.OTEN_REDIRECT_URI);
  authURL.searchParams.set('response_type', 'code');
  authURL.searchParams.set('scope', 'openid profile email');
  authURL.searchParams.set('state', 'test-state');
  
  console.log('Test authorization URL:');
  console.log(authURL.toString());
  
  // You can manually test this URL in a browser
  return authURL.toString();
}

🔍 Configuration Troubleshooting

Common Issues

Invalid Client ID

// Check if client ID is correct
if (error.message.includes('invalid_client')) {
  console.error('❌ Invalid client ID. Check your OTEN_CLIENT_ID');
  console.log('Current client ID:', process.env.OTEN_CLIENT_ID);
}

Redirect URI Mismatch

// Validate redirect URI format
function validateRedirectURI(uri) {
  try {
    const url = new URL(uri);
    
    if (url.protocol !== 'https:' && !url.hostname.includes('localhost')) {
      throw new Error('Redirect URI must use HTTPS in production');
    }
    
    console.log('✅ Redirect URI format valid:', uri);
    return true;
  } catch (error) {
    console.error('❌ Invalid redirect URI:', error.message);
    return false;
  }
}

Debug Configuration

function debugConfiguration() {
  console.log('=== OAuth Configuration Debug ===');
  console.log('Client ID:', process.env.OTEN_CLIENT_ID ? '✅ Set' : '❌ Missing');
  console.log('Client Secret:', process.env.OTEN_CLIENT_SECRET ? '✅ Set' : '❌ Missing');
  console.log('Redirect URI:', process.env.OTEN_REDIRECT_URI);
  console.log('Environment:', process.env.NODE_ENV);
  console.log('================================');
}

Configuration Checklist

Navigation

  • discoveryConfig
    =
    await
    response
    .json
    ();
    return {
    // Client credentials (from Oten registration)
    clientId: process.env.OTEN_CLIENT_ID,
    clientSecret: process.env.OTEN_CLIENT_SECRET,
    // Automatically discovered endpoints
    authorizationURL: discoveryConfig.authorization_endpoint,
    tokenURL: discoveryConfig.token_endpoint,
    userInfoURL: discoveryConfig.userinfo_endpoint,
    jwksURI: discoveryConfig.jwks_uri,
    issuer: discoveryConfig.issuer,
    // Application settings
    redirectURI: process.env.OTEN_REDIRECT_URI,
    scopes: ['openid', 'profile', 'email'],
    // OAuth flow settings
    responseType: 'code',
    grantType: 'authorization_code'
    };
    }
    // Usage
    const config = await createOAuthConfig();

    ← Previous: Step 1: Choose OAuth Library - Select your library

    ↑ Overview: Integration Flow Overview - See the big picture

    → Next: Step 3: Implement Authorization Flow - Implement JAR authorization