Step 1: Choose OAuth Library

The first step in integrating Oten IDP is selecting the right OAuth 2.0 / OpenID Connect library for your technology stack. IMPORTANT: Your chosen library must support JAR (JWT-Secured Authorization Request) as Oten IDP requires it for all authorization requests.

Can't implement JAR? If your application cannot support JAR due to technical constraints, contact [email protected] to discuss enabling traditional OAuth flow as a temporary solution.

📖 Need the big picture? Check out the Integration Flow Overview to understand how this step fits into the complete process.

🎯 What You'll Learn

In this step, you will:

  • Understand JAR (JWT-Secured Authorization Request) requirements

  • Choose libraries that support JAR and JWT signing

  • Install and configure your chosen library with JAR support

  • Understand the trade-offs between different options

🚨 JAR Requirement - CRITICAL

Oten IDP requires JAR (JWT-Secured Authorization Request) for ALL authorization requests. Your chosen library must support:

Required JAR Features

  • JWT Creation and Signing (RS256, HS256, or EdDSA)

  • Custom JWT Claims (ability to add OAuth parameters to JWT payload)

  • Key Management (RSA keys for RS256 or client secret for HS256)

  • Request Parameter Support (sending JWT in request parameter)

❌ Libraries That Won't Work

Libraries that only support traditional OAuth query parameters will NOT work with Oten IDP:

// ❌ This approach will be REJECTED by Oten IDP
const authURL = `https://account.oten.com/v1/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectURI}&response_type=code&scope=openid profile email&state=${state}`;

✅ What You Need

Libraries that can create signed JWTs and send them in the request parameter:

// ✅ This is the ONLY way that works with Oten IDP
const requestJWT = await createJAR(authParams, privateKey);
const authURL = `https://account.oten.com/v1/oauth/authorize?client_id=${clientId}&request=${requestJWT}`;

📚 Library Categories

Official vs Third-Party Libraries

Official Libraries

  • Maintained by platform vendors (Google, Microsoft, etc.)

  • Well-documented and supported

  • Regular security updates

  • Best practices built-in

  • May need custom JAR implementation

Third-Party Libraries

  • Community-maintained

  • Often more flexible

  • May have additional features

  • Varying quality and support levels

  • Check JAR support before choosing

Oten Official Libraries

  • Specifically designed for Oten IDP

  • Built-in JAR support

  • Optimized for Oten features

  • Direct support from Oten team

Client Type Considerations

Confidential Clients (Server-Side)

  • Can securely store client secrets

  • Token exchange happens on server

  • More security options available

  • Examples: Web servers, APIs, backend services

Public Clients (Client-Side)

  • Cannot store secrets securely

  • Must use PKCE for security

  • Tokens handled in browser/device

  • Examples: SPAs, mobile apps, desktop apps

🛠️ Technology-Specific Recommendations

JavaScript/Node.js

For Server-Side (Node.js)

# Recommended: openid-client
npm install openid-client

# Alternative: passport with OAuth strategy
npm install passport passport-oauth2

openid-client - Most comprehensive

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

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

const client = new otenIssuer.Client({
  client_id: 'your-client-id',
  client_secret: 'your-client-secret',
  redirect_uris: ['https://yourapp.com/callback'],
  response_types: ['code'],
});

For Client-Side (Browser/SPA)

# Recommended: oidc-client-ts
npm install oidc-client-ts

# Alternative: auth0-spa-js (more opinionated)
npm install @auth0/auth0-spa-js

oidc-client-ts - Standards compliant

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

const userManager = new UserManager({
  authority: 'https://account.oten.com',
  client_id: 'your-client-id',
  redirect_uri: 'https://yourapp.com/callback',
  response_type: 'code',
  scope: 'openid profile email',
  post_logout_redirect_uri: 'https://yourapp.com',
});

Python

# Most comprehensive: authlib
pip install authlib

# Alternative: requests-oauthlib
pip install requests-oauthlib

# For Django: django-oauth-toolkit
pip install django-oauth-toolkit

# For Flask: flask-oauthlib
pip install flask-oauthlib

Authlib - Modern and comprehensive

from authlib.integrations.flask_client import OAuth

oauth = OAuth(app)
oten = oauth.register(
    name='oten',
    client_id='your-client-id',
    client_secret='your-client-secret',
    server_metadata_url='https://account.oten.com/.well-known/openid_configuration',
    client_kwargs={
        'scope': 'openid profile email'
    }
)

Java

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

Spring Security OAuth2

# application.yml
spring:
  security:
    oauth2:
      client:
        registration:
          oten:
            client-id: your-client-id
            client-secret: your-client-secret
            scope: openid,profile,email
            authorization-grant-type: authorization_code
            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
        provider:
          oten:
            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

Alternative: pac4j

<dependency>
    <groupId>org.pac4j</groupId>
    <artifactId>pac4j-oidc</artifactId>
    <version>5.7.0</version>
</dependency>

C#/.NET

dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect

OpenID Connect Authentication

services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
    options.Authority = "https://account.oten.com";
    options.ClientId = "your-client-id";
    options.ClientSecret = "your-client-secret";
    options.ResponseType = "code";
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Scope.Add("email");
    options.CallbackPath = "/signin-oidc";
});

PHP

# Most popular: league/oauth2-client
composer require league/oauth2-client

# Alternative: thephpleague/oauth2-client
composer require thephpleague/oauth2-client

# For Laravel: laravel/socialite
composer require laravel/socialite

League OAuth2 Client

use League\OAuth2\Client\Provider\GenericProvider;

$provider = new GenericProvider([
    'clientId'                => 'your-client-id',
    'clientSecret'            => 'your-client-secret',
    'redirectUri'             => 'https://yourapp.com/callback',
    'urlAuthorize'            => 'https://account.oten.com/v1/oauth/authorize',
    'urlAccessToken'          => 'https://account.oten.com/v1/oauth/token',
    'urlResourceOwnerDetails' => 'https://account.oten.com/v1/oauth/userinfo',
]);

Go

# Oten go-oauth library with built-in JAR support
go get gitlab.oten.com/go-sdk/go-oauth/client

Oten go-oauth - Official library with JAR support

import (
    "gitlab.oten.com/go-sdk/go-oauth/client"
    "gitlab.oten.com/go-sdk/go-oauth/jar"
)

// Initialize OAuth client with JAR support
config := &client.Config{
    ClientID:     "your-client-id",
    ClientSecret: "your-client-secret", // Optional for public clients
    Endpoint:     client.OtenEndpoint("https://account.oten.com"),
    RedirectURL:  "https://yourapp.com/callback",
    Scopes:       []string{"openid", "profile", "email"},

    // JAR configuration (REQUIRED for Oten IDP)
    JARConfig: &jar.Config{
        SigningMethod: jar.RS256,           // or jar.HS256
        PrivateKey:    loadPrivateKey(),    // RSA private key for RS256
        KeyID:         "your-key-id",       // Key ID from your JWKS
        Issuer:        "your-client-id",    // Usually your client ID
        Audience:      "https://account.oten.com",
    },
}

// Create OAuth client
oauthClient := client.New(config)

// Generate authorization URL with JAR
authURL, err := oauthClient.AuthCodeURL("state-value", client.AccessTypeOffline)
if err != nil {
    log.Fatal(err)
}

// The library automatically creates JAR and sends it in request parameter
fmt.Println("Authorization URL:", authURL)

Key Features of Oten go-oauth:

  • Built-in JAR Support: Automatically creates and signs JWT authorization requests

  • Multiple Signing Methods: Supports RS256 (RSA) and HS256 (HMAC) algorithms

  • PKCE Integration: Automatic PKCE generation for public clients

  • Token Management: Built-in token refresh and validation

  • JWKS Support: Automatic public key publishing

  • Oten Optimized: Designed specifically for Oten IDP features

Alternative: Standard Library (Requires Custom JAR Implementation)

# Standard OAuth2 library (you'll need to implement JAR manually)
go get golang.org/x/oauth2
go get github.com/golang-jwt/jwt/v5  # For JWT creation

Manual JAR Implementation with Standard Library

import (
    "golang.org/x/oauth2"
    "github.com/golang-jwt/jwt/v5"
)

// You'll need to implement JAR creation manually
func createJAR(authParams map[string]interface{}, privateKey interface{}) (string, error) {
    now := time.Now()

    claims := jwt.MapClaims{
        // Standard JWT claims
        "iss": authParams["client_id"],
        "aud": "https://account.oten.com",
        "iat": now.Unix(),
        "exp": now.Add(5 * time.Minute).Unix(),
        "jti": generateUUID(),

        // OAuth parameters
        "client_id":              authParams["client_id"],
        "redirect_uri":           authParams["redirect_uri"],
        "response_type":          authParams["response_type"],
        "scope":                  authParams["scope"],
        "state":                  authParams["state"],
        "code_challenge":         authParams["code_challenge"],
        "code_challenge_method":  authParams["code_challenge_method"],
    }

    token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
    token.Header["kid"] = "your-key-id"

    return token.SignedString(privateKey)
}

// Standard OAuth2 config (without JAR support)
config := &oauth2.Config{
    ClientID:     "your-client-id",
    ClientSecret: "your-client-secret",
    Endpoint: oauth2.Endpoint{
        AuthURL:  "https://account.oten.com/v1/oauth/authorize",
        TokenURL: "https://account.oten.com/v1/oauth/token",
    },
    RedirectURL: "https://yourapp.com/callback",
    Scopes:      []string{"openid", "profile", "email"},
}

// You'll need to manually create JAR and modify the auth URL
authParams := map[string]interface{}{
    "client_id":              config.ClientID,
    "redirect_uri":           config.RedirectURL,
    "response_type":          "code",
    "scope":                  strings.Join(config.Scopes, " "),
    "state":                  "your-state",
    "code_challenge":         "your-code-challenge",
    "code_challenge_method":  "S256",
}

requestJWT, err := createJAR(authParams, privateKey)
if err != nil {
    log.Fatal(err)
}

// Create authorization URL with JAR
authURL := fmt.Sprintf("%s?client_id=%s&request=%s",
    config.Endpoint.AuthURL,
    config.ClientID,
    requestJWT)

Recommendation: Use the Oten go-oauth library as it handles all JAR complexity automatically and is specifically designed for Oten IDP.

Oten go-oauth Library Details

The Oten go-oauth library provides comprehensive OAuth 2.0 and OpenID Connect support with built-in JAR functionality:

Installation:

go get gitlab.oten.com/go-sdk/go-oauth/client

Key Components:

  • client package: Main OAuth client with JAR support

  • jar package: JWT-Secured Authorization Request implementation

  • token package: Token management and validation

  • jwks package: JSON Web Key Set handling

Complete Example:

package main

import (
    "context"
    "fmt"
    "log"

    "gitlab.oten.com/go-sdk/go-oauth/client"
    "gitlab.oten.com/go-sdk/go-oauth/jar"
)

func main() {
    // Load your RSA private key
    privateKey, err := loadRSAPrivateKey("jar-private-key.pem")
    if err != nil {
        log.Fatal(err)
    }

    // Configure OAuth client with JAR
    config := &client.Config{
        ClientID:    "your-client-id",
        RedirectURL: "https://yourapp.com/callback",
        Scopes:      []string{"openid", "profile", "email"},
        Endpoint:    client.OtenEndpoint("https://account.oten.com"),

        // JAR configuration (automatically handled)
        JARConfig: &jar.Config{
            SigningMethod: jar.RS256,
            PrivateKey:    privateKey,
            KeyID:         "your-key-id",
            Issuer:        "your-client-id",
            Audience:      "https://account.oten.com",
        },
    }

    // Create OAuth client
    oauthClient := client.New(config)

    // Generate authorization URL (JAR is automatically created)
    authURL, err := oauthClient.AuthCodeURL("random-state", client.AccessTypeOffline)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("Visit this URL:", authURL)

    // Handle callback (after user authentication)
    // code := "authorization-code-from-callback"
    // token, err := oauthClient.Exchange(context.Background(), code)
    // if err != nil {
    //     log.Fatal(err)
    // }

    // fmt.Printf("Access Token: %s\n", token.AccessToken)
}

Advanced Features:

// Custom JAR claims
jarConfig := &jar.Config{
    SigningMethod: jar.RS256,
    PrivateKey:    privateKey,
    KeyID:         "your-key-id",
    Issuer:        "your-client-id",
    Audience:      "https://account.oten.com",

    // Custom claims
    CustomClaims: map[string]interface{}{
        "ui_locales":     "en-US",
        "prompt":         "consent",
        "workspace_hint": "workspace-123",
    },
}

// PKCE support for public clients
config := &client.Config{
    ClientID:    "your-public-client-id",
    RedirectURL: "https://yourapp.com/callback",
    Scopes:      []string{"openid", "profile", "email"},
    Endpoint:    client.OtenEndpoint("https://account.oten.com"),

    // Enable PKCE for public clients
    UsePKCE: true,

    JARConfig: jarConfig,
}

Ruby

# Most comprehensive: omniauth
gem install omniauth omniauth-oauth2

# Alternative: oauth2 gem
gem install oauth2

# For Rails: omniauth-rails_csrf_protection
gem install omniauth-rails_csrf_protection

OmniAuth

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :oauth2, 'your-client-id', 'your-client-secret',
    client_options: {
      site: 'https://account.oten.com',
      authorize_url: '/v1/oauth/authorize',
      token_url: '/v1/oauth/token'
    }
end

🔍 Library Selection Criteria

JAR Support (CRITICAL for Oten IDP)

MUST HAVE features for Oten IDP integration:

  • JWT Creation and Signing (RS256, HS256, or EdDSA algorithms)

  • Custom JWT Claims (ability to embed OAuth parameters in JWT payload)

  • Request Parameter Support (sending JWT in request parameter)

  • Key Management (RSA private keys or client secrets)

  • JWKS Integration (for public key distribution)

Security Features

Look for libraries that support:

  • JAR (JWT-Secured Authorization Request) - REQUIRED for Oten

  • PKCE (essential for public clients)

  • State parameter validation (CSRF protection)

  • Nonce support (replay attack prevention)

  • JWT validation (signature verification)

  • Token refresh (automatic renewal)

Standards Compliance

Ensure the library supports:

  • JAR RFC 9101 - CRITICAL for Oten IDP

  • OAuth 2.0 RFC 6749

  • OpenID Connect Core 1.0

  • PKCE RFC 7636 (for public clients)

  • JWT RFC 7519

  • JWKS RFC 7517 (for key distribution)

Oten Specific Features

Preferred libraries should support:

  • Oten endpoints (pre-configured)

  • Multi-tenant workspace selection

  • Oten specific scopes

  • Built-in error handling for Oten responses

Maintenance and Support

Consider:

  • Active development (recent commits)

  • Security updates (vulnerability patches)

  • Documentation quality

  • Community support

  • Issue response time

  • Oten compatibility (if available)

📦 Installation Examples

Package Managers

npm (Node.js)

# Install with npm
npm install openid-client

# Install with yarn
yarn add openid-client

# Install with pnpm
pnpm add openid-client

pip (Python)

# Install with pip
pip install authlib

# Install with pipenv
pipenv install authlib

# Install with poetry
poetry add authlib

Maven (Java)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
    <version>2.7.0</version>
</dependency>

NuGet (.NET)

# Package Manager Console
Install-Package Microsoft.AspNetCore.Authentication.OpenIdConnect

# .NET CLI
dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect

⚙️ Configuration Basics

Environment Variables

Set up your configuration securely:

# .env file (never commit to version control)
OTEN_CLIENT_ID=your_client_id_here
OTEN_CLIENT_SECRET=your_client_secret_here
OTEN_REDIRECT_URI=https://yourapp.com/callback

# JAR Configuration (REQUIRED for Oten IDP)
JAR_PRIVATE_KEY_PATH=./jar-private-key.pem
JAR_KEY_ID=your-key-id
JWKS_URI=https://yourapp.com/.well-known/jwks.json

Basic Configuration Structure with JAR

Most libraries need to be configured for JAR support:

const config = {
  // Client credentials
  clientId: process.env.OTEN_CLIENT_ID,
  clientSecret: process.env.OTEN_CLIENT_SECRET, // Optional for public clients

  // Endpoints
  authorizationURL: 'https://account.oten.com/v1/oauth/authorize',
  tokenURL: 'https://account.oten.com/v1/oauth/token',

  // Application settings
  redirectURI: process.env.OTEN_REDIRECT_URI,
  scope: ['openid', 'profile', 'email'],

  // Security settings
  responseType: 'code',
  grantType: 'authorization_code',

  // JAR Configuration (REQUIRED for Oten IDP)
  jar: {
    enabled: true,                                    // JAR is mandatory
    signingMethod: 'RS256',                          // or 'HS256'
    privateKeyPath: process.env.JAR_PRIVATE_KEY_PATH,
    keyId: process.env.JAR_KEY_ID,
    issuer: process.env.OTEN_CLIENT_ID,      // Usually your client ID
    audience: 'https://account.oten.com'
  }
};

JAR-Specific Configuration

Since Oten IDP requires JAR, you'll need additional setup:

// Example for libraries that support JAR
const jarConfig = {
  // JWT signing configuration
  algorithm: 'RS256',                    // Recommended: RS256 with RSA keys
  privateKey: fs.readFileSync(process.env.JAR_PRIVATE_KEY_PATH),
  keyId: process.env.JAR_KEY_ID,

  // JWT claims
  issuer: process.env.OTEN_CLIENT_ID,
  audience: 'https://account.oten.com',
  expirationTime: 300,                   // 5 minutes (recommended)

  // JWKS endpoint for public key distribution
  jwksUri: process.env.JWKS_URI
};

🔧 Testing Your Library Choice

Quick Test Setup for JAR Support

  1. Install the library

  2. Set up JAR configuration (private key, JWKS endpoint)

  3. Create a simple JAR authorization request

  4. Test the JWT creation and signing

  5. Verify the authorization URL format

  6. Test the complete OAuth flow

JAR Testing Checklist

General Validation Checklist

Test JAR Implementation

// Quick test to verify JAR capability
async function testJARSupport() {
  try {
    // Test JWT creation
    const authParams = {
      client_id: 'test-client',
      redirect_uri: 'https://test.com/callback',
      response_type: 'code',
      scope: 'openid profile email',
      state: 'test-state'
    };

    const requestJWT = await createJAR(authParams);
    console.log('✅ JAR creation successful');

    // Test authorization URL format
    const authURL = `https://account.oten.com/v1/oauth/authorize?client_id=test-client&request=${requestJWT}`;
    console.log('✅ Authorization URL format correct');

    return true;
  } catch (error) {
    console.error('❌ JAR test failed:', error);
    return false;
  }
}

Progress: Step 1 of 5 complete ✅

Last updated