Skip to Content

OIDC Configuration Guide

This guide explains how to configure the OIDC module in IOTA SDK.

Environment Variables

Required Variables

Add these variables to your .env file:

# OIDC Issuer URL (must match your domain) OIDC_ISSUER_URL=https://your-domain.com # Crypto key for encrypting signing keys (32+ characters recommended) OIDC_CRYPTO_KEY=your-very-secure-random-key-here-32-chars-minimum # Database: SDK builds the connection from DB_NAME, DB_HOST, DB_PORT, DB_USER, DB_PASSWORD (see installation). Use the same DB for OIDC. DB_NAME=dbname DB_HOST=localhost DB_PORT=5432 DB_USER=user DB_PASSWORD=password

Optional Variables (supported in central config)

# Token lifetimes (defaults shown) OIDC_ACCESS_TOKEN_LIFETIME=1h # 1 hour OIDC_ID_TOKEN_LIFETIME=1h # 1 hour OIDC_REFRESH_TOKEN_LIFETIME=720h # 30 days

Other OIDC-related variables (e.g. OIDC_AUTH_CODE_LIFETIME, OIDC_REQUIRE_PKCE, OIDC_ALLOWED_ORIGINS, OIDC_RATE_LIMIT_*) are not present in the central pkg/configuration OIDCOptions; they may be used by other layers or not yet implemented.

Crypto Key Generation

The OIDC_CRYPTO_KEY is used to encrypt RSA private keys before storing them in the database.

Generate a Secure Crypto Key

Option 1: Using OpenSSL

openssl rand -base64 32

Option 2: Using Python

import secrets print(secrets.token_urlsafe(32))

Option 3: Using Node.js

crypto.randomBytes(32).toString('base64')

Important Security Notes

  1. Never commit the crypto key to version control
  2. Use different keys for development, staging, and production
  3. Store the key in a secure secret management system (AWS Secrets Manager, HashiCorp Vault, etc.)
  4. Rotate the key periodically (see Key Rotation section below)

Key Rotation

When rotating the crypto key:

  1. Generate a new crypto key
  2. Decrypt existing signing keys with old crypto key
  3. Re-encrypt with new crypto key
  4. Update OIDC_CRYPTO_KEY in environment
  5. Restart the application

Token Lifetime Configuration

Default Token Lifetimes

Token TypeDefault LifetimeRecommended Range
Access Token1 hour15 minutes - 1 hour
ID Token1 hour15 minutes - 1 hour
Refresh Token30 days7 days - 90 days
Authorization Code5 minutes1 minute - 10 minutes

Per-Client Token Lifetimes

You can configure custom lifetimes for specific clients:

-- Set custom token lifetimes for a client UPDATE oidc_clients SET access_token_lifetime = INTERVAL '30 minutes', id_token_lifetime = INTERVAL '30 minutes', refresh_token_lifetime = INTERVAL '7 days' WHERE client_id = 'my-client-id';

Lifetime Tuning Guidelines

Short-lived Access Tokens (15-30 minutes):

  • Better security (reduced window for token theft)
  • Encourages token refresh
  • More frequent token refreshes
  • Higher load on token endpoint

Long-lived Access Tokens (2-24 hours):

  • Fewer token refreshes
  • Better performance
  • Longer vulnerability window
  • Not recommended for sensitive applications

Refresh Token Lifetime:

  • Mobile apps: 30-90 days
  • Web apps: 7-30 days
  • Backend services: No refresh tokens (use client credentials)

Multi-Tenant Considerations

Tenant Isolation

OIDC module respects multi-tenant architecture:

  1. Clients are global (not tenant-specific)
  2. Auth requests include tenant_id after user authentication
  3. Refresh tokens are scoped to user + tenant + client
  4. User info returns data for authenticated tenant only

Security Best Practices

Variables such as OIDC_RATE_LIMIT_*, OIDC_ALLOWED_ORIGINS, OIDC_AUTH_CODE_LIFETIME, and OIDC_REQUIRE_PKCE are not part of the central pkg/configuration OIDCOptions. They may be implemented by other layers or not yet functional—verify support in your deployment before relying on them.

1. Client Configuration

Public Clients (SPAs, Mobile Apps):

INSERT INTO oidc_clients (client_id, name, application_type, redirect_uris, require_pkce) VALUES ( 'spa-client', 'My SPA Application', 'spa', ARRAY['http://localhost:3000/callback'], true -- ALWAYS true for public clients );

Confidential Clients (Backend Services):

INSERT INTO oidc_clients ( client_id, name, application_type, redirect_uris, client_secret_hash, require_pkce ) VALUES ( 'backend-client', 'My Backend Service', 'web', ARRAY['https://api.example.com/callback'], '$2a$10$hashed_secret_here', -- Use bcrypt false -- Optional for confidential clients );

2. Redirect URI Validation

Strict Validation Rules:

  • Exact match required (no wildcards)
  • HTTPS required in production
  • Localhost allowed only in development
  • Do not use http:// in production
  • Do not use wildcard subdomains

Example:

-- Good: Exact URLs redirect_uris = ARRAY['https://app.example.com/callback'] -- Bad: Wildcards (not supported) redirect_uris = ARRAY['https://*.example.com/callback'] -- Development only redirect_uris = ARRAY['http://localhost:3000/callback']

3. Scope Configuration

Recommended Scopes:

ScopeDescriptionRequired?
openidOpenID Connect authenticationYes (always)
profileUser profile info (name, picture)Recommended
emailUser email addressRecommended
offline_accessRefresh tokenOptional

Custom Scopes:

-- Add custom scopes for specific clients UPDATE oidc_clients SET scopes = ARRAY['openid', 'profile', 'email', 'custom:read', 'custom:write'] WHERE client_id = 'my-client';

4. Rate Limiting

Note: These variables are not part of central pkg/configuration and may require custom implementation.

Protect endpoints from abuse:

# In .env OIDC_RATE_LIMIT_ENABLED=true # Per-endpoint limits OIDC_RATE_LIMIT_AUTHORIZE=100 # per 15 min per IP OIDC_RATE_LIMIT_TOKEN=50 # per 15 min per client OIDC_RATE_LIMIT_USERINFO=200 # per 15 min per token

5. CORS Configuration

Note: OIDC_ALLOWED_ORIGINS is not part of central pkg/configuration and may require custom implementation.

Configure CORS for browser-based clients:

# Allow specific origins OIDC_ALLOWED_ORIGINS=https://app.example.com,https://admin.example.com # DO NOT use wildcard in production OIDC_ALLOWED_ORIGINS=* # INSECURE

6. Token Storage

Client-side storage guidelines:

Storage TypeAccess TokensRefresh TokensID Tokens
MemoryBestNoOK
LocalStorageXSS riskNeverLow risk
SessionStorageOKNeverOK
HttpOnly CookieBestBestOK
Secure CookieBestBestOK

7. Client Secret Management

Generate strong client secrets:

# 64-character random secret openssl rand -hex 32

Hash secrets before storage:

import "golang.org/x/crypto/bcrypt" hashedSecret, _ := bcrypt.GenerateFromPassword([]byte(secret), bcrypt.DefaultCost)

Production Checklist

Before deploying to production:

  • OIDC_CRYPTO_KEY is secure and stored in secret manager
  • All redirect URIs use HTTPS (no http://)
  • PKCE is required for public clients
  • Token lifetimes are configured appropriately
  • Rate limiting is enabled
  • CORS is configured with specific origins (no wildcard)
  • Client secrets are hashed with bcrypt
  • Monitoring and alerting are configured
  • Backup and recovery procedures are documented
  • Key rotation procedure is documented
  • Security audit has been performed

Troubleshooting

Common Issues

Issue: “invalid_client” error

  • Check client_id and client_secret are correct
  • Verify client exists in database
  • Ensure client is active (is_active = true)

Issue: “invalid_redirect_uri” error

  • Redirect URI must exactly match registered URI
  • Check for trailing slashes
  • Verify protocol (http vs https)

Issue: “invalid_grant” error

  • Authorization code may have expired (5 min default)
  • Code may have already been used (one-time use)
  • Verify code_verifier matches code_challenge (PKCE)

Issue: Signing key errors

  • Bootstrap keys: make db migrate up
  • Verify OIDC_CRYPTO_KEY is set correctly
  • Check database connectivity

Issue: Token refresh fails

  • Verify refresh token has not expired
  • Check client_id matches original authorization
  • Ensure refresh token hasn’t been revoked

Additional Resources

Last updated on