> For the complete documentation index, see [llms.txt](https://oten.gitbook.io/identity-support/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://oten.gitbook.io/identity-support/integration/prerequisites/pkce-implementation-guide/step-2-configure-oauth-client.md).

# Step 2: Configure OAuth Client

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](broken://pages/iMMrTD1lQOMbxxvheKAz) 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](broken://pages/tVlOClAh8Jnn50qts43R) for complete implementation examples.

```javascript
// Automatic configuration using discovery
async function createOAuthConfig() {
  const discoveryUrl = 'https://account.oten.com/.well-known/openid-configuration';
  const response = await fetch(discoveryUrl);
  const 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();
```

### Method 2: Manual Configuration

If you prefer to configure endpoints manually:

```javascript
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

```javascript
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

Many libraries support automatic configuration via the discovery endpoint:

```javascript
// 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

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

```bash
# 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

```javascript
// 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

```javascript
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

```python
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

```yaml
# 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

```csharp
// 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)

For applications that can securely store secrets:

```javascript
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)

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

```javascript
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

```javascript
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

```javascript
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

```javascript
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

```javascript
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

```javascript
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

```javascript
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

```javascript
// 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

```javascript
// 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

```javascript
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

Before proceeding to the next step, ensure:

* [ ] Environment variables are set correctly
* [ ] Client ID and secret are valid
* [ ] Redirect URI matches registration
* [ ] Endpoints are accessible
* [ ] Scopes are appropriate for your use case
* [ ] Security settings are configured properly
* [ ] Configuration validation passes

***

## Navigation

* **← Previous**: [Step 1: Choose OAuth Library](broken://pages/CuJNdfiNnGHuqh7gDIK2) - Select your library
* **↑ Overview**: [Integration Flow Overview](broken://pages/iMMrTD1lQOMbxxvheKAz) - See the big picture
* **→ Next**: [Step 3: Implement Authorization Flow](broken://pages/1zKgOda9hrWwNX8K6Zea) - Implement JAR authorization

**Progress**: Step 2 of 5 complete ✅
