Configuration

Configuration (bohurupee.yaml)

Bohurupee loads YAML once at startup as a sparse overlay on the built-in default config (same content as bohurupee init / bohurupee.example.yaml: Alice, Bob, Carol, and the stock provider profiles). Omitted keys keep their defaults, except personas, which is required in every config file. With no --config flag it uses ./bohurupee.yaml when that file exists; otherwise it runs with those built-ins on port 4190, bind 127.0.0.1.

bohurupee init                  # write ./bohurupee.yaml
bohurupee                       # load ./bohurupee.yaml if present
bohurupee --config ./other.yaml

While the process is running, apply file changes without restart (loopback only):

curl -s -X POST http://127.0.0.1:4190/__reload

Reload updates personas, PKCE, idToken, openClient, refreshTokens, clients, and providerProfiles. It does not change the listen address or OIDC signing key. Invalid YAML leaves the previous config in place and returns an error JSON body.

CLI --bind / --port override the file for the current process only.


Full example

This matches the shipped bohurupee.example.yaml, with optional keys shown in comments:

port: 4190
bind: 127.0.0.1
pkce: optional          # optional | required | forbidden
idToken: openid         # openid | always
openClient: true
# refreshTokens: false  # default; set true to issue refresh_token
# clients:
#   - id: my-app
#     redirect_uris:
#       - http://127.0.0.1:3000/api/auth/callback/bohurupee

personas:
  - id: alice
    email: [email protected]
    name: Alice Admin
    nickname: alice
    claims:
      role: admin
  - id: bob
    email: [email protected]
    name: Bob User
    email_verified: false
    claims:
      role: user
  - id: carol
    email: [email protected]
    name: Carol Reviewer
    nickname: carol
    avatar: ""
    response:
      picture: ""

providerProfiles:
  github:
    responseTemplate: github
  google:
    responseTemplate: google
  facebook:
    responseTemplate: facebook
    endpoints:
      userinfo: /me
  apple:
    responseTemplate: apple
    protocol:
      response_mode: form_post
      id_token: true

Top-level keys

port

Type integer
Default 4190
Reload ignored (listen address fixed at startup)

TCP port to listen on. 0 in the file falls back to the CLI default.

port: 4190

Equivalent flag: --port 4190.


bind

Type string
Default 127.0.0.1
Reload ignored

Host interface to bind. Non-loopback addresses are refused unless you pass --dangerously-bind-all-interfaces (or run the Docker image, which binds 0.0.0.0 inside the container on purpose).

In Docker, a loopback bind from the YAML (127.0.0.1, localhost, ::1) is upgraded to 0.0.0.0 so -p publishing works. The rest of the config still loads. An explicit --bind always wins.

bind: 127.0.0.1
# only with --dangerously-bind-all-interfaces (outside Docker)
bind: 0.0.0.0

Equivalent flag: --bind 127.0.0.1.

When --config is omitted, Bohurupee looks for ./bohurupee.yaml. In Docker it also tries /bohurupee.yaml and /config/bohurupee.yaml, or BOHURUPEE_CONFIG if set.


pkce

Type string
Default optional
Values optional, required, forbidden
Reload yes

Controls Proof Key for Code Exchange on authorize / token.

Value Authorize Token
optional Challenge allowed but not required Verifier checked when a challenge was sent
required code_challenge must be present Matching code_verifier required
forbidden Challenge rejected —
pkce: optional
pkce: required   # force S256 (or plain) on every login
pkce: forbidden  # reject clients that send a challenge

Supported challenge methods: S256 and plain.


idToken

Type string
Default openid
Values openid, always
Reload yes

When the token response includes an RS256 id_token.

Value Behavior
openid Issue id_token when the authorize scope contains openid
always Always issue id_token, even without openid

A provider profile may also force tokens with protocol.id_token: true (Apple in the example config).

idToken: openid
idToken: always

Claims on the JWT include iss, sub, aud, iat, exp, email, email_verified, name, given_name, family_name, nickname, picture, optional nonce, at_hash, and non-reserved keys from persona claims.


openClient

Type boolean
Default true
Reload yes

Open local client mode.

Value Behavior
true Any client_id works. If that id is listed under clients with redirect_uris, those URIs are enforced. Unlisted clients accept any absolute http/https redirect.
false Every client_id must appear under clients. Clients with redirect_uris must use one of those URIs.
openClient: true
openClient: false
clients:
  - id: strict-app
    redirect_uris:
      - http://127.0.0.1:3000/callback

Secrets are never validated either way.


refreshTokens

Type boolean
Default false
Reload yes

Opt-in refresh tokens. When false (default), the token JSON has no refresh_token field and discovery lists only authorization_code.

When true:

  • Code exchange may return refresh_token
  • Discovery adds refresh_token to grant_types_supported
  • grant_type=refresh_token issues a new access token (same refresh token reused)
refreshTokens: false
refreshTokens: true

Access tokens last 1 hour; refresh tokens last 24 hours (in memory).


personas

Type list of objects
Default Alice, Bob, Carol when no config file is loaded
Reload yes

Required in every config file. An omitted personas key is an error (the built-in list is not inherited). An empty list is also an error. Each persona is a fake user you can pick on the consent page or select with ?auto=<id>.

Persona fields

id (required)

URL-safe slug: letters, digits; after the first character also - and _. Used in consent, auto=, and stable subject ids ({provider}:{id}).

- id: alice

email

Email claim on userinfo and id_token.

  email: [email protected]

email_verified

Type boolean
Default true when omitted
  email_verified: false

name

Display name. Split into given_name / family_name on templates and id_token (“Alice Admin” → Alice / Admin).

  name: Alice Admin

nickname

Short handle. Defaults to id when omitted. Often mapped to Socialite getNickname() / GitHub login.

  nickname: alice

avatar

Profile image URL.

Omission Result
Key omitted Dicebear identicon: https://api.dicebear.com/9.x/identicon/svg?seed={id}
avatar: "" Empty string (missing picture tests)
Non-empty string That URL
  avatar: https://example.com/alice.png
  avatar: ""

claims

Arbitrary JSON object merged into userinfo and id_token (except reserved JWT keys such as iss, sub, aud, exp, iat, nonce, at_hash).

  claims:
    role: admin
    org_id: "42"

response

Overlay map applied last in the userinfo merge (can clear getters). String values may use placeholders: {{id}}, {{sub}}, {{email}}, {{name}}, {{nickname}}, {{avatar}}, {{provider}}.

  response:
    picture: ""
    title: "{{nickname}}"

Persona examples

Admin with role claim:

personas:
  - id: alice
    email: [email protected]
    name: Alice Admin
    nickname: alice
    claims:
      role: admin

Unverified email:

  - id: bob
    email: [email protected]
    name: Bob User
    email_verified: false
    claims:
      role: user

No avatar (Socialite / UI empty-picture cases):

  - id: carol
    email: [email protected]
    name: Carol Reviewer
    nickname: carol
    avatar: ""
    response:
      picture: ""

clients

Type list of objects
Default none (open client)
Reload yes

Optional registered OAuth clients. Duplicate id values are rejected.

Client fields

id (required)

Must match the authorize / token client_id.

redirect_uris

Exact-match allowlist. When non-empty, authorize rejects any other redirect_uri for this client (HTTP 400, no redirect).

clients:
  - id: my-app
    redirect_uris:
      - http://127.0.0.1:3000/api/auth/callback/bohurupee
      - http://localhost:3000/api/auth/callback/bohurupee

With openClient: true, clients not listed here still accept any valid redirect. With openClient: false, unlisted client_id values are rejected.


providerProfiles

Type map keyed by provider slug
Default stock profiles from bohurupee.example.yaml (Apple form_post, Facebook /me, …)
Reload yes

Per-slug userinfo shape, extra routes, and protocol defaults. Key must be a valid provider slug (same rules as persona id). Entries in your file merge into the stock profile for that slug; omitted slugs stay as defaults.

See Provider profiles for merge order and the full template table. Summary of profile fields:

responseTemplate

Built-in template name: github, google, facebook, generic, …
Unknown names are rejected at load / reload.

providerProfiles:
  github:
    responseTemplate: github

response

Custom JSON merged into userinfo (supports {{placeholders}}).

  staffdir:
    response:
      title: Engineer
      username: "{{nickname}}"

endpoints

Extra paths. Today userinfo registers an alias on that provider:

  facebook:
    responseTemplate: facebook
    endpoints:
      userinfo: /me    # also GET /facebook/me
Note

Userinfo alias routes are registered when the process starts. Adding a new alias via reload updates rendering for existing routes; a new path may need a process restart to appear on the mux.

protocol

Defaults when the authorize query omits the matching parameter:

Key Values Effect
response_mode query (default), form_post How code / error return to the app
id_token true / false Force id_token on token response
  apple:
    responseTemplate: apple
    protocol:
      response_mode: form_post
      id_token: true

The client can still pass response_mode=query explicitly.


What is not in the YAML

Concern Where it lives
Listen override --bind, --port, --dangerously-bind-all-interfaces
Auto-approve every authorize env BOHURUPEE_AUTO_APPROVE=1
OIDC signing key ~/…/bohurupee/oidc.key (created on first run)
Codes / tokens Process memory only

Minimal configs

No file — built-in Alice / Bob / Carol on 127.0.0.1:4190:

bohurupee

A config file must include personas. Other keys stay at the defaults:

pkce: required
port: 5190
personas:
  - id: alice
    email: [email protected]
    name: Alice
  - id: bob
    email: [email protected]
    name: Bob
    email_verified: false

Partial provider profile (merges into the stock entry):

personas:
  - id: alice
    email: [email protected]
    name: Alice
providerProfiles:
  apple:
    protocol:
      response_mode: query

Strict local app:

openClient: false
clients:
  - id: next-local
    redirect_uris:
      - http://localhost:3000/api/auth/callback/bohurupee
personas:
  - id: alice
    email: [email protected]
    name: Alice Admin
Edit this page