API Reference

Base URL: https://oidc.pub/api

POST /services

Register a new OIDC service. Free and Team services receive a random URL name inside the customer's tenant suffix. Business and Enterprise customers may set serviceName, which is used as the URL name before the tenant suffix.

{ "title": "string", "serviceName?": "string", "description?": "string" }

GET /services

List all services owned by the authenticated user.

GET /services/{subdomain}

Get details for a specific service by subdomain. Legacy UUID service IDs are still accepted for compatibility.

GET /services/{subdomain}/config

Read the currently published OIDC configuration and JWKS for a service. Legacy UUID service IDs are still accepted for compatibility.

PUT /services/{subdomain}/config

Upload OIDC configuration and JWKS for a service. The issuer and jwks_uri are rewritten to the oidc.pub subdomain. Changes propagate globally within 60 seconds. Legacy UUID service IDs are still accepted for compatibility.

{ "openidConfiguration": { ... }, "jwks": { "keys": [...] } }

DELETE /services/{subdomain}/config

Remove the published OIDC configuration and JWKS for a service without deleting the service itself. Legacy UUID service IDs are still accepted for compatibility.

DELETE /services/{subdomain}

Remove a service and its public OIDC configuration. Legacy UUID service IDs are still accepted for compatibility.

Anonymous Services

Anonymous services are temporary services for unauthenticated use. They expire after at most 24 hours, receive a random -anon subdomain, and are managed with a one-time secret returned by the create call. Store the secret immediately; it is not returned again.

POST /anonymous/services

Create a temporary anonymous service. No account session is required.

{ "title?": "string", "description?": "string", "ttlHours?": 24 }

The response includes the service, management secret, dashboard URL, expiry time, and remaining lifetime:

{
  "service": { "id": "...", "subdomain": "abc12345-anon", "name": "abc12345-anon" },
  "secret": "oidcpub_anon_...",
  "dashboardUrl": "https://oidc.pub/dashboard/anonymous/abc12345-anon#secret=oidcpub_anon_...",
  "expiresAt": "2026-06-10T18:00:00.000Z",
  "remainingSeconds": 86400
}

Manage with /services/{subdomain}

After creation, use the regular service endpoints with the management secret as Authorization: Bearer <secret>. The secret is scoped to that anonymous service only.

Supported anonymous management endpoints:

  • GET /services/{subdomain} — get details and remaining lifetime
  • PATCH /services/{subdomain} — update title and/or description
  • PUT /services/{subdomain}/config — upload OIDC configuration and JWKS
  • GET /services/{subdomain}/config — read published OIDC configuration and JWKS
  • DELETE /services/{subdomain}/config — remove published OIDC configuration and JWKS
  • DELETE /services/{subdomain} — delete the anonymous service and published config
{ "openidConfiguration": { ... }, "jwks": { "keys": [...] } }

Service Accounts

A Service Account is a programmatic identity. Its policy decides which services it can act on and how it authenticates:

  • kind: "static" — issues a long-lived bearer token. Send Authorization: Bearer oidcpub_… on subsequent calls.
  • kind: "oidc" — accepts JWTs minted by an external OIDC provider (GitHub Actions, GitLab CI, etc.) and authorizes them against rule-based claim matchers.

The policy is a JSON document validated against https://oidc.pub/schemas/service-account-policy.v1.json. Reference the URL in your policy file via $schema and most editors will give you autocomplete and inline diagnostics.

POST /service-accounts

Create a Service Account. For static policies the response includes a one-time token — store it immediately, it is never returned again.

{
  "name": "CI/CD Pipeline",
  "policy": {
    "$schema": "https://oidc.pub/schemas/service-account-policy.v1.json",
    "kind": "static",
    "services": ["*"],
    "ip_allowlist": ["10.0.0.0/8"]
  }
}

OIDC example:

{
  "name": "GitHub Actions",
  "policy": {
    "$schema": "https://oidc.pub/schemas/service-account-policy.v1.json",
    "kind": "oidc",
    "rules": [
      {
        "services": ["ci-staging"],
        "claims": {
          "iss": "https://token.actions.githubusercontent.com",
          "aud": "https://oidc.pub",
          "sub": "repo:myorg/myrepo:ref:refs/heads/main"
        }
      }
    ]
  }
}

Notes:

  • services entries are service subdomains. "*" matches every service you own; partial globs like "acme-*" are accepted. Non-wildcard entries are validated against your owned services on save — typos and references to services you don't control are rejected with 400. At request time, an EXISTS join inside the lookup table ensures a JWT can only authorize against services owned by the SA's customer, even if the policy is services: ["*"].
  • Inside claims, every value supports * globs except iss, which must be the exact issuer URL.
  • aud and sub are required. Add any additional claim keys as needed (e.g. repository_owner, ref); each is checked against the corresponding JWT claim.
  • ip_allowlist accepts IPv4 / IPv6 addresses and CIDR ranges. Omit the field (or use []) to allow all source IPs.

GET /service-accounts

List all Service Accounts owned by the authenticated user.

GET /service-accounts/{id}

Get a single Service Account, including its current policy.

PATCH /service-accounts/{id}

Update name and/or policy. The kind of the policy cannot be changed — delete and recreate to switch between static and oidc.

DELETE /service-accounts/{id}

Permanently delete the Service Account. Any token it issued stops working immediately.

POST /service-accounts/{id}/regenerate-token

Regenerate the bearer token for a static Service Account. The previous token is invalidated atomically. OIDC accounts have no token to regenerate.