> 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/appendix/configuration-reference.md).

# Configuration Reference

## OpenID Connect Discovery

Oten IDP provides OpenID Connect Discovery endpoints that automatically provide all configuration information your application needs. This is the **recommended way** to get configuration details.

### Discovery Endpoints

#### Production Environment

```
Discovery URL: https://account.oten.com/.well-known/openid-configuration
```

#### Sandbox Environment

```
Discovery URL: https://account.sbx.oten.dev/.well-known/openid-configuration
```

### How to Use Discovery

Instead of hardcoding endpoints, fetch configuration dynamically:

```javascript
// Fetch configuration automatically
async function getOIDCConfiguration(environment = 'production') {
  const discoveryUrl = environment === 'production'
    ? 'https://account.oten.com/.well-known/openid-configuration'
    : 'https://account.sbx.oten.dev/.well-known/openid-configuration';

  const response = await fetch(discoveryUrl);
  const config = await response.json();

  return {
    issuer: config.issuer,
    authorizationEndpoint: config.authorization_endpoint,
    tokenEndpoint: config.token_endpoint,
    jwksUri: config.jwks_uri,
    supportedScopes: config.scopes_supported,
    supportedResponseTypes: config.response_types_supported,
    supportedGrantTypes: config.grant_types_supported,
    supportedCodeChallengeMethods: config.code_challenge_methods_supported,
    supportedTokenAuthMethods: config.token_endpoint_auth_methods_supported,
    supportedClaims: config.claims_supported,
    supportedIdTokenSigningAlgs: config.id_token_signing_alg_values_supported
  };
}

// Usage example
const config = await getOIDCConfiguration('development');
console.log('Authorization Endpoint:', config.authorizationEndpoint);
console.log('Token Endpoint:', config.tokenEndpoint);
console.log('Supported Scopes:', config.supportedScopes);
```

### 🔧 Configuration Response Format

The discovery endpoint returns a JSON object with the following structure:

```json
{
  "issuer": "https://account.sbx.oten.dev",
  "authorization_endpoint": "https://account.sbx.oten.dev/v1/oauth/authorize",
  "token_endpoint": "https://account.sbx.oten.dev/v1/oauth/token",
  "jwks_uri": "https://account.sbx.oten.dev/.well-known/jwks.json",
  "response_types_supported": ["code"],
  "subject_types_supported": ["public"],
  "id_token_signing_alg_values_supported": ["EdDSA"],
  "scopes_supported": ["openid", "profile", "email"],
  "token_endpoint_auth_methods_supported": ["client_secret_post"],
  "claims_supported": ["sub", "name", "email"],
  "code_challenge_methods_supported": ["S256", "plain"],
  "grant_types_supported": ["authorization_code", "refresh_token"]
}
```

### Configuration Parameters Explained

| Parameter                               | Description                        | Oten Values                                                    |
| --------------------------------------- | ---------------------------------- | -------------------------------------------------------------- |
| `issuer`                                | Identity provider identifier       | `https://account.[env].oten.dev` or `https://account.oten.com` |
| `authorization_endpoint`                | OAuth authorization URL            | `/v1/oauth/authorize`                                          |
| `token_endpoint`                        | Token exchange URL                 | `/v1/oauth/token`                                              |
| `jwks_uri`                              | Public keys for token verification | `/.well-known/jwks.json`                                       |
| `response_types_supported`              | Supported OAuth response types     | `["code"]`                                                     |
| `subject_types_supported`               | Subject identifier types           | `["public"]`                                                   |
| `id_token_signing_alg_values_supported` | ID token signing algorithms        | `["EdDSA"]`                                                    |
| `scopes_supported`                      | Available OAuth scopes             | `["openid", "profile", "email"]`                               |
| `token_endpoint_auth_methods_supported` | Client authentication methods      | `["client_secret_post"]`                                       |
| `claims_supported`                      | Available user claims              | `["sub", "name", "email"]`                                     |
| `code_challenge_methods_supported`      | PKCE challenge methods             | `["S256", "plain"]`                                            |
| `grant_types_supported`                 | Supported OAuth grant types        | `["authorization_code", "refresh_token"]`                      |

## 🌐 Manual Endpoint Configuration

If you prefer to configure endpoints manually (not recommended), here are the static endpoints:

### Production Environment

```
Base Domain: oten.com
Authorization Server: https://account.oten.com
Token Endpoint: https://account.oten.com/v1/oauth/token
Authorization Endpoint: https://account.oten.com/v1/oauth/authorize
Token Validation: https://account.oten.com/v1/token/validate
User Info: https://account.oten.com/v1/userinfo
JWKS URI: https://account.oten.com/.well-known/jwks.json
OIDC Discovery: https://account.oten.com/.well-known/openid-configuration
```

### Sandbox Environment

```
Base Domain: oten.dev
Authorization Server: https://account.sbx.oten.dev
Token Endpoint: https://account.sbx.oten.dev/v1/oauth/token
Authorization Endpoint: https://account.sbx.oten.dev/v1/oauth/authorize
Token Validation: https://account.sbx.oten.dev/v1/token/validate
User Info: https://account.sbx.oten.dev/v1/userinfo
JWKS URI: https://account.sbx.oten.dev/.well-known/jwks.json
OIDC Discovery: https://account.sbx.oten.dev/.well-known/openid-configuration
```

## 🛠️ Library-Specific Configuration Examples

### Node.js with Passport.js

```javascript
const passport = require('passport');
const { Strategy: OIDCStrategy } = require('passport-openidconnect');

// Configure using discovery URL
passport.use('oten', new OIDCStrategy({
  issuer: 'https://account.sbx.oten.dev',
  authorizationURL: 'https://account.sbx.oten.dev/v1/oauth/authorize',
  tokenURL: 'https://account.sbx.oten.dev/v1/oauth/token',
  userInfoURL: 'https://account.sbx.oten.dev/v1/userinfo',
  clientID: process.env.OTEN_CLIENT_ID,
  clientSecret: process.env.OTEN_CLIENT_SECRET,
  callbackURL: process.env.OTEN_REDIRECT_URI,
  scope: ['openid', 'profile', 'email']
}, (issuer, profile, done) => {
  return done(null, profile);
}));
```

### Python with Authlib

```python
from authlib.integrations.flask_client import OAuth

oauth = OAuth(app)

# Configure using discovery URL
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.sbx.oten.dev/.well-known/openid-configuration',
    client_kwargs={
        'scope': 'openid profile email',
        'code_challenge_method': 'S256'  # Enable PKCE
    }
)
```

### Java with Spring Security

```java
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public ClientRegistrationRepository clientRegistrationRepository() {
        return new InMemoryClientRegistrationRepository(otenClientRegistration());
    }

    private ClientRegistration otenClientRegistration() {
        return ClientRegistration.withRegistrationId("oten")
                .clientId(System.getenv("OTEN_CLIENT_ID"))
                .clientSecret(System.getenv("OTEN_CLIENT_SECRET"))
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
                .scope("openid", "profile", "email")
                .issuerUri("https://account.sbx.oten.dev")
                .build();
    }
}
```

### React SPA with OIDC Client

```javascript
import { UserManager } from 'oidc-client-ts';

const userManager = new UserManager({
  authority: 'https://account.sbx.oten.dev',
  client_id: process.env.REACT_APP_CLIENT_ID,
  redirect_uri: `${window.location.origin}/callback`,
  response_type: 'code',
  scope: 'openid profile email',
  post_logout_redirect_uri: window.location.origin,

  // PKCE is automatically enabled
  automaticSilentRenew: true,
  silent_redirect_uri: `${window.location.origin}/silent-callback`,

  // Discovery will automatically fetch endpoints
  metadata: {
    issuer: 'https://account.sbx.oten.dev',
    authorization_endpoint: 'https://account.sbx.oten.dev/v1/oauth/authorize',
    token_endpoint: 'https://account.sbx.oten.dev/v1/oauth/token',
    userinfo_endpoint: 'https://account.sbx.oten.dev/v1/userinfo',
    jwks_uri: 'https://account.sbx.oten.dev/.well-known/jwks.json'
  }
});
```

### .NET Core

```csharp
public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddCookie()
    .AddOpenIdConnect(options =>
    {
        options.Authority = "https://account.sbx.oten.dev";
        options.ClientId = Configuration["Oten:ClientId"];
        options.ClientSecret = Configuration["Oten:ClientSecret"];
        options.ResponseType = "code";
        options.Scope.Add("openid");
        options.Scope.Add("profile");
        options.Scope.Add("email");
        options.SaveTokens = true;
        options.UsePkce = true; // Enable PKCE
    });
}
```

## 🔄 Dynamic Configuration Loading

### Environment-Aware Configuration

```javascript
class OtenConfig {
  constructor(environment = 'development') {
    this.environment = environment;
    this.config = null;
  }

  async loadConfiguration() {
    const discoveryUrl = this.getDiscoveryUrl();

    try {
      const response = await fetch(discoveryUrl);
      if (!response.ok) {
        throw new Error(`Failed to fetch configuration: ${response.status}`);
      }

      this.config = await response.json();
      return this.config;
    } catch (error) {
      console.error('Failed to load OIDC configuration:', error);
      // Fallback to static configuration
      return this.getFallbackConfiguration();
    }
  }

  getDiscoveryUrl() {
    const baseUrl = this.environment === 'production'
      ? 'https://account.oten.com'
      : 'https://account.sbx.oten.dev';

    return `${baseUrl}/.well-known/openid-configuration`;
  }

  getFallbackConfiguration() {
    const baseUrl = this.environment === 'production'
      ? 'https://account.oten.com'
      : 'https://account.sbx.oten.dev';

    return {
      issuer: baseUrl,
      authorization_endpoint: `${baseUrl}/v1/oauth/authorize`,
      token_endpoint: `${baseUrl}/v1/oauth/token`,
      jwks_uri: `${baseUrl}/.well-known/jwks.json`,
      userinfo_endpoint: `${baseUrl}/v1/userinfo`,
      scopes_supported: ['openid', 'profile', 'email'],
      response_types_supported: ['code'],
      grant_types_supported: ['authorization_code', 'refresh_token']
    };
  }

  async getEndpoint(type) {
    if (!this.config) {
      await this.loadConfiguration();
    }

    const endpoints = {
      authorization: this.config.authorization_endpoint,
      token: this.config.token_endpoint,
      userinfo: this.config.userinfo_endpoint,
      jwks: this.config.jwks_uri
    };

    return endpoints[type];
  }

  async getSupportedFeatures() {
    if (!this.config) {
      await this.loadConfiguration();
    }

    return {
      scopes: this.config.scopes_supported || [],
      responseTypes: this.config.response_types_supported || [],
      grantTypes: this.config.grant_types_supported || [],
      codeChallengeMethod: this.config.code_challenge_methods_supported || [],
      tokenAuthMethods: this.config.token_endpoint_auth_methods_supported || [],
      claims: this.config.claims_supported || []
    };
  }
}

// Usage
const config = new OtenConfig('development');
await config.loadConfiguration();

const authEndpoint = await config.getEndpoint('authorization');
const supportedScopes = await config.getSupportedFeatures();
console.log('Available scopes:', supportedScopes.scopes);
```

## Official Contact Information

### Support Channels

* **Technical Support**: <support@oten.live>

### Developer Resources

* **Developer Portal**: <https://developer.oten.com> *(Coming Soon)*
* **API Documentation**: <https://docs.oten.com> *(Coming Soon)*
* **Status Page**: <https://status.oten.com> *(Coming Soon)*

## Rate Limits

### Production Limits

* **Authorization endpoint**: 10 requests/minute per IP
* **Token endpoint**: 60 requests/minute per client
* **Validation endpoint**: 1000 requests/minute per client
* **User Info endpoint**: 100 requests/minute per token

### Development Limits

* **Authorization endpoint**: 20 requests/minute per IP
* **Token endpoint**: 120 requests/minute per client
* **Validation endpoint**: 2000 requests/minute per client
* **User Info endpoint**: 200 requests/minute per token

## 🔐 Supported Algorithms and Methods

### JAR Signing Algorithms

* **HS256**: HMAC with SHA-256 (uses client\_secret)
* **EdDSA**: Edwards-curve Digital Signature with Ed25519

### Token Signing Algorithms

* **EdDSA**: Edwards-curve Digital Signature (for ID tokens and access tokens)

### PKCE Code Challenge Methods

* **S256**: SHA256 hash of code verifier (recommended)
* **plain**: Plain text code verifier (not recommended for production)

### Client Authentication Methods

* **client\_secret\_post**: Client credentials in request body (default)

### Supported Response Types

* **code**: Authorization code flow (only supported type)

### Supported Grant Types

* **authorization\_code**: Standard OAuth 2.0 authorization code flow
* **refresh\_token**: Token refresh using refresh tokens

## Supported Scopes and Claims

### Available Scopes

Based on the discovery endpoint, Oten IDP currently supports:

* **`openid`**: Required for OpenID Connect flow - enables ID token issuance
* **`profile`**: Access to basic profile information (name, etc.)
* **`email`**: Access to user's email address

### Available Claims

The following claims are available in ID tokens and UserInfo endpoint:

* **`sub`**: Subject identifier - unique user ID
* **`name`**: User's full name
* **`email`**: User's email address

### Scope-to-Claims Mapping

| Scope     | Claims Included | Description                                      |
| --------- | --------------- | ------------------------------------------------ |
| `openid`  | `sub`           | Minimum required scope, provides user identifier |
| `profile` | `sub`, `name`   | Adds user's display name                         |
| `email`   | `sub`, `email`  | Adds user's email address                        |

### Example Scope Requests

```javascript
// Minimum required scope
scope: "openid"

// Basic user information
scope: "openid profile"

// Full user information
scope: "openid profile email"
```

### Future Scopes (Coming Soon)

Additional scopes may be added in future releases:

* `phone`: Phone number access
* `offline_access`: Refresh token capability
* `workspace`: Workspace information access

## Testing and Validation

### Validate Discovery Endpoint

```bash
# Test discovery endpoint
curl -s https://account.sbx.oten.dev/.well-known/openid-configuration | jq .

# Check specific configuration values
curl -s https://account.sbx.oten.dev/.well-known/openid-configuration | jq '.scopes_supported'
```

### Validate JWKS Endpoint

```bash
# Test JWKS endpoint
curl -s https://account.sbx.oten.dev/.well-known/jwks.json | jq .
```

### Configuration Validation Script

```javascript
async function validateOtenConfiguration(environment = 'development') {
  const baseUrl = environment === 'production'
    ? 'https://account.oten.com'
    : 'https://account.sbx.oten.dev';

  console.log(`Validating Oten IDP configuration for ${environment}...`);

  try {
    // Test discovery endpoint
    const discoveryResponse = await fetch(`${baseUrl}/.well-known/openid-configuration`);
    if (!discoveryResponse.ok) {
      throw new Error(`Discovery endpoint failed: ${discoveryResponse.status}`);
    }

    const config = await discoveryResponse.json();
    console.log('✅ Discovery endpoint accessible');

    // Validate required fields
    const requiredFields = [
      'issuer', 'authorization_endpoint', 'token_endpoint',
      'jwks_uri', 'scopes_supported', 'response_types_supported'
    ];

    const missingFields = requiredFields.filter(field => !config[field]);
    if (missingFields.length > 0) {
      throw new Error(`Missing required fields: ${missingFields.join(', ')}`);
    }
    console.log('✅ All required configuration fields present');

    // Test JWKS endpoint
    const jwksResponse = await fetch(config.jwks_uri);
    if (!jwksResponse.ok) {
      throw new Error(`JWKS endpoint failed: ${jwksResponse.status}`);
    }

    const jwks = await jwksResponse.json();
    if (!jwks.keys || jwks.keys.length === 0) {
      throw new Error('JWKS endpoint has no keys');
    }
    console.log('✅ JWKS endpoint accessible and has keys');

    // Validate supported features
    const validations = [
      {
        name: 'Authorization Code Flow',
        check: config.response_types_supported.includes('code'),
        message: 'Authorization code flow is supported'
      },
      {
        name: 'PKCE Support',
        check: config.code_challenge_methods_supported &&
               config.code_challenge_methods_supported.includes('S256'),
        message: 'PKCE with S256 is supported'
      },
      {
        name: 'OpenID Connect',
        check: config.scopes_supported.includes('openid'),
        message: 'OpenID Connect is supported'
      },
      {
        name: 'Client Secret Post',
        check: config.token_endpoint_auth_methods_supported.includes('client_secret_post'),
        message: 'Client secret post authentication is supported'
      }
    ];

    validations.forEach(validation => {
      if (validation.check) {
        console.log(`✅ ${validation.message}`);
      } else {
        console.log(`❌ ${validation.name} validation failed`);
      }
    });

    console.log('\nConfiguration Summary:');
    console.log(`Issuer: ${config.issuer}`);
    console.log(`Authorization Endpoint: ${config.authorization_endpoint}`);
    console.log(`Token Endpoint: ${config.token_endpoint}`);
    console.log(`Supported Scopes: ${config.scopes_supported.join(', ')}`);
    console.log(`Supported Claims: ${config.claims_supported.join(', ')}`);

    return config;

  } catch (error) {
    console.error('❌ Configuration validation failed:', error.message);
    throw error;
  }
}

// Usage
validateOtenConfiguration('development')
  .then(() => console.log('\nConfiguration validation completed successfully'))
  .catch(error => console.error('\nConfiguration validation failed:', error.message));
```

### Health Check Script

```javascript
async function healthCheck(environment = 'development') {
  const baseUrl = environment === 'production'
    ? 'https://account.oten.com'
    : 'https://account.sbx.oten.dev';

  const endpoints = [
    { name: 'Discovery', url: `${baseUrl}/.well-known/openid-configuration` },
    { name: 'JWKS', url: `${baseUrl}/.well-known/jwks.json` },
    { name: 'Authorization', url: `${baseUrl}/v1/oauth/authorize`, method: 'HEAD' }
  ];

  console.log(`Health check for ${environment} environment...`);

  for (const endpoint of endpoints) {
    try {
      const response = await fetch(endpoint.url, {
        method: endpoint.method || 'GET',
        timeout: 5000
      });

      if (response.ok) {
        console.log(`✅ ${endpoint.name}: OK (${response.status})`);
      } else {
        console.log(`⚠️ ${endpoint.name}: ${response.status} ${response.statusText}`);
      }
    } catch (error) {
      console.log(`❌ ${endpoint.name}: ${error.message}`);
    }
  }
}
```

## Error Codes Reference

**Complete Reference**: See [Error Codes Reference](broken://pages/bJ3yHAB6ah0s2qAer3PL) for comprehensive error documentation with troubleshooting guides.

### Quick Error Reference

**Most Common Errors:**

| Error Code               | Endpoint      | Description                              | Action Required          |
| ------------------------ | ------------- | ---------------------------------------- | ------------------------ |
| `invalid_request`        | Authorization | Missing request parameter or JAR expired | Implement/regenerate JAR |
| `invalid_request_object` | Authorization | Invalid JAR token                        | Fix JAR implementation   |
| `invalid_grant`          | Token         | Authorization code/refresh token invalid | Restart auth flow        |
| `invalid_client`         | Token         | Client auth failed or IP not whitelisted | Check credentials/IP     |
| `unauthorized_client`    | Token         | Client not authorized for grant type     | Use correct client type  |
| `server_error`           | Both          | Internal server error                    | Retry with backoff       |

### Error Response Formats

**Authorization Endpoint:**

```
Location: https://yourapp.com/callback?error=invalid_request&error_description=Request%20parameter%20is%20required&state=xyz
```

**Token Endpoint:**

```json
{
  "error": "invalid_grant",
  "error_description": "Invalid authorization code: code expired"
}
```

### Error Handling Guidelines

* **Always validate `state` parameter** in authorization callbacks
* **Implement retry logic** for `server_error` and `temporarily_unavailable`
* **Don't retry** for `invalid_grant`, `invalid_client`, or configuration errors
* **Log detailed errors** server-side for debugging
* **Provide user-friendly messages** based on error codes

### Security-Enhanced Error Handling

**JAR (JWT-Secured Authorization Request) Requirements:**

* Either `request` OR `request_uri` parameter is REQUIRED
* Cannot provide both `request` and `request_uri` parameters simultaneously
* Missing `request` parameter results in `invalid_request` with message "Request parameter is required"

**IP Address Validation (Client Credentials Grant):**

* IP address validation is enforced when whitelist is configured
* Requests from non-whitelisted IPs receive `invalid_client` error
* Missing IP address triggers security warnings

**Client Type Enforcement:**

* Client credentials grant restricted to confidential clients only
* Public clients receive `unauthorized_client` error
* Client type validation occurs before credential verification

### Related Documentation

* [**Error Codes Reference**](broken://pages/bJ3yHAB6ah0s2qAer3PL): Complete error documentation
* [**Common Errors**](broken://pages/ChQqcK8cqX9LLgyQtBJT): Step-by-step troubleshooting
* [**OAuth Error Handling**](https://gitlab.silvertiger.tech/documents/idp/-/blob/main/best-practices/oauth-error-handling.md): Implementation examples

## Security Requirements

### Mandatory Security Features

* **PKCE**: Required for all public clients, recommended for confidential clients
* **JAR**: Required for confidential clients only, forbidden for public clients
* **HTTPS**: Required for all endpoints (except localhost in development)
* **State Parameter**: Required to prevent CSRF attacks

### Token Lifetimes

* **Authorization Code**: 10 minutes
* **Access Token**: 1 hour (configurable)
* **Refresh Token**: 30 days (configurable)
* **ID Token**: 1 hour
* **JAR Token**: 5 minutes maximum

## Client Registration Requirements

### Required Information

* Application name
* Application type (Web App, SPA, Mobile App, Server-to-Server)
* Redirect URIs (must be HTTPS except localhost)
* Required scopes
* JAR signing method (HS256 or EdDSA)

### Optional Information

* Application description
* Application logo URL
* Terms of service URL
* Privacy policy URL
* JWKS URI (for EdDSA)
