# 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 ✅


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://oten.gitbook.io/identity-support/integration/prerequisites/pkce-implementation-guide/step-2-configure-oauth-client.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
