Skip to main content

Overview

Proxy Hopper supports OIDC (OpenID Connect) for SSO integration with enterprise identity providers including Authentik, Azure AD, Keycloak, Okta, and any other OIDC-compliant IdP. With OIDC, users authenticate directly with your identity provider and present the resulting JWT to Proxy Hopper. Proxy Hopper validates the token and reads a role claim to determine access.

Configuration

auth:
  enabled: true
  jwtSecret: "change-me-to-a-long-random-string"   # for locally-issued tokens if also using local admin

  oidc:
    issuerUrl: "https://auth.example.com/application/o/proxy-hopper/"
    clientId: "proxy-hopper"
    clientSecret: "my-client-secret"
    roleClaimPath: "proxy_hopper_role"   # claim name in the JWT that holds the role
    audience: "proxy-hopper"             # optional — validate the 'aud' claim

  roles:
    data-team:
      targets: ["analytics", "general"]
    maps-team:
      targets: ["maps", "geocoding"]

Fields

FieldTypeDescription
oidc.issuerUrlstringOIDC discovery URL — /.well-known/openid-configuration is appended automatically
oidc.clientIdstringClient ID registered with your IdP
oidc.clientSecretstringClient secret (for token introspection, if used)
oidc.roleClaimPathstringJWT claim that contains the user’s role name
oidc.audiencestringExpected aud claim value — recommended for security

How it works

  1. User authenticates with the identity provider using the client credentials or authorization code flow
  2. IdP issues a JWT containing the role claim
  3. User sends the JWT in X-Proxy-Hopper-Auth: Bearer <token>
  4. Proxy Hopper validates the token signature against the IdP’s JWKS endpoint (fetched from the discovery URL)
  5. Proxy Hopper reads the role from roleClaimPath and checks access to the requested target

Role claim

The JWT must contain a claim matching roleClaimPath. The claim value must be one of:
  • A built-in role name: admin, operator, viewer
  • A custom role name defined in auth.roles
{
  "sub": "user@example.com",
  "proxy_hopper_role": "data-team",
  "exp": 1700000000
}
If the role claim is missing or names an unknown role, the request is rejected with 403.

Client credentials flow

For service-to-service access via OIDC (machine-to-machine):
# Exchange client credentials for a token
TOKEN=$(curl -s -X POST "https://auth.example.com/application/o/token/" \
  -d "grant_type=client_credentials" \
  -d "client_id=my-service" \
  -d "client_secret=my-secret" \
  -d "scope=openid" \
  | jq -r '.access_token')

# Use the token
curl -H "X-Proxy-Hopper-Target: https://api.example.com" \
     -H "X-Proxy-Hopper-Auth: Bearer $TOKEN" \
     http://proxy-hopper:8080/v1/endpoint

Combining SSO with local admin

You can use OIDC for service access while keeping a local admin account for emergency access:
auth:
  enabled: true
  jwtSecret: "change-me-to-a-long-random-string"

  admin:
    username: admin
    passwordHash: "$2b$12$..."   # fallback local account

  oidc:
    issuerUrl: "https://auth.example.com/application/o/proxy-hopper/"
    clientId: "proxy-hopper"
    clientSecret: "my-client-secret"
    roleClaimPath: "proxy_hopper_role"
Local admin login continues to work via /auth/login on the admin port, independently of OIDC.

Provider-specific setup

Step-by-step guides for popular identity providers:

Authentik

Set up a service account, configure a property mapping, and issue client credentials.

Azure Active Directory

Register an app, configure roles claim, and use client credentials flow.