Connected Apps

Connected Apps are OAuth 2.0 clients registered with Bulwark. When an application registers as a Connected App, Bulwark becomes its authorization server — issuing access tokens, enforcing scopes, and enabling agents to act on users' behalf within that application.

What Is a Connected App?

Any application that needs to participate in Bulwark's auth ecosystem can register as a Connected App:

  • Your own app — register to enable users to authorize agents to act on their behalf
  • Third-party integrations — allow external tools to request scoped access to your data
  • Agentic services — headless clients that use client_credentials to authenticate as themselves

Each Connected App receives a client_id and client_secret. These credentials are used at Bulwark's token endpoint to obtain access tokens.

Dynamic Client Registration

Apps can self-register using Dynamic Client Registration (RFC 7591). This is useful for:

  • Platform customers who provision their own apps programmatically
  • Marketplace integrations that register at install time
  • Development tooling that needs transient clients
const response = await fetch("https://api.bulwarkauth.com/oauth2/register", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Bulwark-Tenant": tenantId,
  },
  body: JSON.stringify({
    client_name: "My Integration",
    redirect_uris: ["https://app.example.com/auth/callback"],
    grant_types: ["authorization_code", "refresh_token"],
    scope: "read:reports",
  }),
});

const { client_id, client_secret } = await response.json();

Tenants can restrict DCR to callers who present a valid initial access token, preventing arbitrary public registration.

Grant Types

Authorization Code + PKCE

Used when a human user needs to authorize an app or an agent acting on their behalf. The user is redirected to Bulwark's hosted login, consents to the requested scopes, and is redirected back with an authorization code.

App → GET /oauth2/authorize?client_id=...&scope=...&code_challenge=...
  ↓
User authenticates and consents at Bulwark
  ↓
Redirect to redirect_uri with ?code=...
  ↓
App → POST /oauth2/token (code + code_verifier)
  ↓
App receives access_token + refresh_token

Client Credentials

Used by headless services or agents that authenticate as themselves (not on behalf of a user). No user interaction is required.

const { access_token } = await fetch("https://api.bulwarkauth.com/oauth2/token", {
  method: "POST",
  body: new URLSearchParams({
    grant_type: "client_credentials",
    client_id: process.env.CLIENT_ID,
    client_secret: process.env.CLIENT_SECRET,
    scope: "read:metrics write:alerts",
  }),
}).then(r => r.json());

Consent Flow

For authorization_code grants, Bulwark presents a consent screen to the user listing the scopes being requested. The user can approve or deny.

Consent decisions are cached per (user, client_id, scope) tuple. Repeat authorizations with the same scopes skip the consent screen. If the app requests new scopes, the user is prompted again for only those additional scopes.

Consent can be pre-approved for first-party apps, bypassing the screen entirely.

Scopes

Connected Apps define the scopes they are allowed to request. A client cannot request scopes beyond what was declared at registration. Scopes map to the permissions Bulwark enforces on the access token:

| Scope | Description | |-------|-------------| | read:profile | Read the authenticated user's profile | | read:customers | Read customer records | | write:reports | Create and update reports | | agent:act | Allow an agent to act on behalf of this user |

Token Lifecycle

Access tokens issued to Connected Apps are short-lived (default: 1 hour). Refresh tokens are long-lived and can be used to obtain new access tokens without user interaction.

Tokens are revoked when:

  • The user revokes app authorization from their account settings
  • The app is deleted or revoked by a tenant admin
  • The user account is deactivated

Agents as Connected App Clients

An agent can be configured to use a Connected App's client_credentials grant. This means the agent authenticates as the app — not as a user — and can only access resources the app is authorized to reach. This is the recommended pattern for background agents that process data without a user context.