OAuth2 Plugin

The OAuth2 plugin provides authentication using OAuth2 providers (Google, GitHub, Azure AD, etc.), integrating seamlessly with Rusty Beam's authorization system.

Overview

This plugin implements the OAuth2 authorization code flow for authentication with any OAuth2-compliant provider. It handles login, callback, logout, and status endpoints while maintaining session state. The plugin sets the authenticated_user metadata that can be used by the authorization plugin for access control decisions.

Key Features

Configuration

Add the OAuth2 plugin to your host configuration before the authorization plugin:

<!-- Google OAuth2 configuration -->
<td itemprop="plugin" itemscope itemtype="https://rustybeam.net/schema/OAuth2Plugin">
    <span itemprop="library">file://./plugins/librusty_beam_oauth2.so</span>
    <span itemprop="clientIdEnv">GOOGLE_CLIENT_ID</span>
    <span itemprop="clientSecretEnv">GOOGLE_CLIENT_SECRET</span>
    <span itemprop="redirectUriEnv">GOOGLE_OAUTH2_CALLBACK</span>
</td>

<!-- GitHub OAuth2 configuration with custom login path -->
<td itemprop="plugin" itemscope itemtype="https://rustybeam.net/schema/OAuth2Plugin">
    <span itemprop="library">file://./plugins/librusty_beam_oauth2.so</span>
    <span itemprop="name">github-oauth2</span>
    <span itemprop="clientIdEnv">GITHUB_CLIENT_ID</span>
    <span itemprop="clientSecretEnv">GITHUB_CLIENT_SECRET</span>
    <span itemprop="redirectUriEnv">GITHUB_REDIRECT_URI</span>
    <span itemprop="loginPath">/auth/github/signin</span>
</td>

Configuration Parameters

Parameter Type Required Default Description
clientIdEnv String Yes - Environment variable name to read OAuth2 client ID from
clientSecretEnv String Yes - Environment variable name to read OAuth2 client secret from
redirectUriEnv String Yes - Environment variable name to read OAuth2 redirect URI from
name String No oauth2 Plugin instance name
loginPath String No /auth/{name}/login Path where login requests will be handled
⚠️ Plugin Pipeline Placement
This plugin MUST be placed before the authorization plugin in the pipeline. It sets the authenticated_user metadata that the authorization plugin uses for access control decisions.

Environment Variables

The plugin reads all OAuth2 configuration from environment variables for security. You must specify which environment variables to use via the clientIdEnv, clientSecretEnv, and redirectUriEnv configuration parameters.

Multiple OAuth2 Providers: You can use this plugin multiple times with different OAuth2 providers by configuring different environment variable names. For example, you could have one instance reading from GOOGLE_CLIENT_ID and another reading from GITHUB_CLIENT_ID.

OAuth2 Provider Setup

Example setup for common providers:

Google

  1. Go to Google Cloud Console
  2. Create OAuth 2.0 credentials
  3. Add redirect URI to authorized URIs

GitHub

  1. Go to GitHub Settings → Developer settings → OAuth Apps
  2. Register a new OAuth application
  3. Set authorization callback URL

Azure AD

  1. Go to Azure Portal → App registrations
  2. Register new application
  3. Add redirect URI under Authentication

Endpoints

The plugin provides the following endpoints:

Endpoint Method Description Response
{loginPath} GET Initiates OAuth2 flow 302 redirect to OAuth provider
{callback path} GET OAuth2 callback handler 302 redirect to return URL or /
/auth/logout POST Destroys session 302 redirect to return URL or /
/auth/user GET Returns current user information HTML with schema.org/Person microdata
Dynamic Endpoints:

Examples

HTML Login Button

<!-- Default login path -->
<a href="/auth/oauth2/login?return_to=/dashboard" class="login-btn">
    Login with OAuth
</a>

<!-- Custom login path (when loginPath is configured) -->
<a href="/auth/github/signin?return_to=/dashboard" class="login-btn">
    Login with GitHub
</a>

JavaScript Authentication Check

async function checkAuth() {
    const response = await fetch('/auth/user');
    
    if (response.ok) {
        const html = await response.text();
        const parser = new DOMParser();
        const doc = parser.parseFromString(html, 'text/html');
        
        // Extract user info from microdata
        const userEl = doc.querySelector('[itemtype="https://schema.org/Person"]');
        if (userEl) {
            const email = userEl.querySelector('[itemprop="email"]')?.textContent;
            const name = userEl.querySelector('[itemprop="name"]')?.textContent;
            console.log(`Logged in as: ${name} (${email})`);
            // Show authenticated UI
        }
    } else {
        // User not authenticated - show login button
    }
}

User Endpoint Response Format

The /auth/user endpoint returns HTML with schema.org/Person microdata when a user is authenticated:

<!DOCTYPE html>
<html>
<head>
    <title>User Information</title>
</head>
<body>
    <div itemscope itemtype="https://schema.org/Person">
        <p>Email: <span itemprop="email">user@example.com</span></p>
        <p>Name: <span itemprop="name">John Doe</span></p>
        <p>Image: <span itemprop="image">https://example.com/avatar.jpg</span></p>
    </div>
</body>
</html>
Note: If no user is authenticated, the plugin will not respond and the request will pass through to other plugins in the pipeline.

Logout Implementation

async function logout() {
    const response = await fetch('/auth/logout?return_to=/', {
        method: 'POST'
    });
    
    if (response.ok) {
        window.location.href = '/';
    }
}

Using with Authorization Rules

In your authorization configuration, you can grant permissions to specific users by email:

<tr itemscope itemtype="https://rustybeam.net/schema/AuthorizationRule">
    <td itemprop="username">user@gmail.com</td>
    <td itemprop="path">/admin/*</td>
    <td></td>
    <td><ul><li itemprop="method">GET</li></ul></td>
    <td itemprop="action">allow</td>
</tr>

Integration with Other Plugins

The OAuth2 plugin integrates primarily with:

Session Management

Sessions are managed in-memory with the following characteristics:

Design Note: The current implementation stores sessions in memory. For production use, consider implementing persistent session storage (e.g., Redis) or session expiration.

Security Considerations

Troubleshooting

Issue Possible Cause Solution
500 Error on login Missing client_id or client_secret Ensure OAuth2 credentials are configured correctly
Invalid redirect URI error Mismatch between configured and provider URIs Verify redirect_uri matches exactly in both places
403 on callback Invalid or missing state parameter Check for cookie issues or middleware interference
User not authorized after login Plugin order incorrect Ensure OAuth2 plugin is before authorization plugin

Debug Logging

Enable verbose mode to see detailed OAuth2 flow information:

cargo run -- -v config/config.html

Limitations

See Also