Docs menu: OIDC discovery
Provider strategy

vestibule_oidc

OpenID Connect discovery that auto-configures a strategy from any standards-compliant issuer URL, including self-hosted providers.

When to use it

Use OIDC discovery when you want to authenticate against any OpenID Connect provider — including self-hosted ones — by pointing at its issuer URL instead of hand-wiring endpoints.

Default scopes: openid profile email

Install

Until 1.0, install Vestibule packages from GitHub using the movingvestibule-v0.0 tag. This requires Gleam 1.18 or later because companion packages use git path dependencies.

[dependencies]
vestibule_oidc = { git = "https://github.com/tylerbutler/vestibule.git", ref = "vestibule-v0.0", path = "packages/vestibule_oidc" }

Setup

  1. Register a client with your OIDC provider and copy the client ID and secret.
  2. Configure the redirect URI to match the one passed to config.new.
  3. Call discover with the provider's issuer URL to fetch its well-known configuration.
  4. Pair the discovered strategy with config.new holding your client credentials.

Usage

import vestibule
import vestibule/config
import vestibule_oidc

// Discover the provider's endpoints from its issuer URL.
let assert Ok(strategy) =
  vestibule_oidc.discover("https://accounts.google.com")

let client_config =
  config.new(
    client_id: "your-client-id",
    redirect_uri: "https://myapp.example.com/auth/oidc/callback",
    auth: config.ClientSecret("your-client-secret"),
  )

let options = config.authorize_options()
let assert Ok(auth_request) =
  vestibule.create_authorization_request(
    strategy,
    config: client_config,
    options: options,
  )

What Vestibule handles

  • One-step discover reads /.well-known/openid-configuration and builds a Strategy.
  • Issuer validation rejects discovery documents whose issuer does not match the requested URL.
  • HTTPS and public-host enforcement on issuer and endpoints guards against SSRF.
  • Standard OIDC claims (sub, name, email, preferred_username, picture) map to UserInfo.
  • Email is only populated when the provider reports email_verified.

What you handle

  • Discovery performs HTTP requests, so the strategy targets the Erlang (BEAM) runtime only.
  • Store authorization_request.nonce(auth_request) and pass it as `expected_nonce` during callback handling.
  • For multi-tenant apps, sanitize user-supplied issuer URLs before calling discover to prevent SSRF.