Documentation

Everything you need to know about using Schlussel for authentication.

📋 Formula Specification

Formulas are JSON files that describe how to authenticate with a provider. They contain everything needed: OAuth endpoints, auth methods, API definitions, and optional public clients.

Root Fields

Field Required Description
schema Yes Version identifier. Must be "v2".
id Yes Unique identifier (e.g., github, stripe). Used in CLI commands and storage keys.
label Yes Human-readable name for display.
description Yes Brief description of the provider and supported auth methods.
methods Yes Object defining authentication methods (see below).
apis Yes Object defining API endpoints.
clients No Array of public OAuth clients that can be used without registration.
identity No Hints for multi-account scenarios (label and hint text).

Methods

Each method defines an authentication flow. Common method names:

  • authorization_code - OAuth with browser redirect (has endpoints.authorize + endpoints.token)
  • device_code - OAuth device flow (has endpoints.device + endpoints.token)
  • mcp_oauth - MCP OAuth with dynamic registration (has dynamic_registration object)
  • api_key / personal_access_token - Manual credential (has script with copy_key)
Field Description
label Human-readable name for the method.
endpoints OAuth endpoints: authorize, token, device, registration.
scope Space-separated OAuth scopes.
register Instructions for manual app registration (url and steps array).
script Array of steps guiding the user through authentication.
dynamic_registration RFC 7591 client registration parameters.

Script Steps

Type Description Value
open_url User should open a URL URL or {placeholder}
enter_code User should enter a code Code or {user_code}
copy_key User should paste an API key -
wait_for_callback Wait for OAuth callback -
wait_for_token Poll for device code completion -

Placeholders

Placeholder Description
{authorize_url} Full authorization URL with parameters
{verification_uri} URL to enter device code
{verification_uri_complete} URL with code pre-filled
{user_code} Code user enters at verification URL

APIs

Each API defines an endpoint that can be called with tokens from specified methods:

Field Required Description
base_url Yes API base URL.
auth_header Yes How to pass the token (e.g., Authorization: Bearer {token}).
methods Yes Array of method names that produce valid tokens.
docs_url No Link to API documentation.
spec_url No Link to machine-readable spec.
spec_type No Type of spec: openapi, graphql, asyncapi.

Public Clients

Clients bundled with the formula that users can use without registering their own OAuth app:

Field Required Description
name Yes Identifier for the client.
id Yes OAuth client ID.
secret No OAuth client secret (for confidential clients).
source No URL where this client ID was found.
methods No Which methods this client supports (default: all OAuth methods).
redirect_uri No Fixed redirect URI required by this client.

Storage Keys

Tokens are stored using a conventional key format:

{formula_id}:{method}:{identity}

Examples:

  • github:device_code:personal - GitHub device code token for "personal" identity
  • linear:authorization_code:acme - Linear OAuth token for "acme" workspace
  • stripe:api_key - Stripe API key (no identity)

Example Formula

{
  "schema": "v2",
  "id": "github",
  "label": "GitHub",
  "description": "Authenticate with GitHub using OAuth device code flow...",
  "apis": {
    "rest": {
      "base_url": "https://api.github.com",
      "auth_header": "Authorization: Bearer {token}",
      "docs_url": "https://docs.github.com/en/rest",
      "spec_type": "openapi"
    }
  },
  "clients": [
    {
      "name": "gh-cli",
      "id": "178c6fc778ccc68e1d6a",
      "secret": "34ddeff2b558a23d38fba...",
      "source": "https://github.com/cli/cli",
      "methods": ["device_code", "authorization_code"]
    }
  ],
  "identity": {
    "label": "Account",
    "hint": "e.g., personal, work"
  },
  "methods": {
    "device_code": {
      "endpoints": {
        "device": "https://github.com/login/device/code",
        "token": "https://github.com/login/oauth/access_token"
      },
      "scope": "repo read:org gist",
      "script": [
        { "type": "open_url", "value": "{verification_uri}" },
        { "type": "enter_code", "value": "{user_code}" },
        { "type": "wait_for_token" }
      ]
    },
    "personal_access_token": {
      "register": {
        "url": "https://github.com/settings/tokens/new",
        "steps": ["Generate a new token", "Copy the token"]
      },
      "script": [
        { "type": "copy_key", "note": "Paste your GitHub PAT" }
      ]
    }
  }
}

💻 CLI Reference

The Schlussel CLI is the primary interface for authenticating with providers and managing tokens.

Installation

# Using mise (recommended)
mise use -g github:pepicrft/schlussel

# Or build from source
git clone https://github.com/pepicrft/schlussel
cd schlussel && zig build

Commands

schlussel run <formula>

Authenticate with a provider and obtain a token.

Option Description
-m, --method <str> Authentication method (required if multiple methods available).
-c, --client <str> Use a public client from the formula.
-r, --redirect-uri <str> Redirect URI for auth code flow (default: http://127.0.0.1:0/callback).
-f, --formula-json <str> Load a custom formula JSON file.
--client-id <str> Override OAuth client ID.
--client-secret <str> Override OAuth client secret.
-s, --scope <str> OAuth scopes (space-separated).
--credential <str> Secret for non-OAuth methods (api_key).
-i, --identity <str> Identity label for storage key (e.g., workspace name).
--open-browser <true|false> Open the authorization URL automatically (default: true).
-j, --json Emit machine-readable JSON output.
-n, --dry-run Show auth steps and URLs without executing. Useful for previewing the flow.
Auto-selection
When a formula has a public client, Schlussel auto-selects it. If only one method is available, it is auto-selected too.

schlussel token <action>

Token management operations.

Action Description
get Retrieve a stored token. Requires --key or --formula.
list List all stored tokens. Can be filtered.
delete Delete a stored token. Requires --key or --formula.

Options:

Option Description
-k, --key <str> Full token storage key (e.g., github:device_code:personal).
--formula <str> Filter/query by formula ID (e.g., github).
--method <str> Filter/query by auth method (e.g., device_code).
--identity <str> Filter/query by identity label (e.g., personal).
--no-refresh Disable auto-refresh. By default, OAuth2 tokens are refreshed if expired or expiring soon, using cross-process locking.
-j, --json Output in JSON format.
Auto-refresh with locking
By default, schlussel token get automatically refreshes OAuth2 tokens that are expired or expiring soon. It acquires a cross-process lock before refreshing, ensuring that if multiple processes request the same token simultaneously, only one performs the refresh while others wait and receive the updated token. Use --no-refresh to disable this behavior.

Examples

# Authenticate with GitHub (auto-selects public client and method)
schlussel run github

# Preview auth flow without executing
schlussel run github --dry-run

# Authenticate with a specific method
schlussel run github --method device_code

# Use a specific public client
schlussel run github --client gh-cli

# Authenticate with Linear for a specific workspace
schlussel run linear --method authorization_code --identity acme

# Use a custom formula file
schlussel run acme --formula-json ~/formulas/acme.json

# Get JSON output for scripting
schlussel run github --json

# List all tokens
schlussel token list

# List tokens for a specific formula
schlussel token list --formula github

# Get token using key components (auto-refreshes if expiring)
schlussel token get --formula github --method device_code

# Get token without auto-refresh
schlussel token get --formula github --method device_code --no-refresh

# Get token as JSON
schlussel token get --formula github --method device_code --json

# Delete a token
schlussel token delete --key github:device_code:personal