Skip to content

Setup API

The Setup API handles first-run instance configuration. All mutating endpoints require a valid setup session token and are permanently disabled after the instance reaches ready state.

For a walkthrough of the setup process, see Set Up Your Instance. For the state machine reference, see Setup States.

Setup Status

Retrieve the current setup state. This endpoint is always public and returns only non-sensitive information.

GET /v1/public/setup-status

Authentication: None (public)

State requirement: Available in all states (including ready)

Response

json
{
  "instance_id": "550e8400-e29b-41d4-a716-446655440000",
  "state": "bootstrap_pending",
  "setup_mode": true,
  "is_configured": false
}
FieldTypeDescription
instance_idstringUUID of this Oore CI instance
statestringCurrent setup state: uninitialized, bootstrap_pending, idp_configured, owner_created, or ready
setup_modebooleantrue when setup is not yet complete
is_configuredbooleantrue when state is ready

Example

bash
curl http://127.0.0.1:8787/v1/public/setup-status

Verify Bootstrap Token

Verify the one-time bootstrap token generated by oore setup token. On success, consumes the token and returns a setup session token.

POST /v1/setup/bootstrap-token/verify

Authentication: None (public)

State requirement: Any state except ready

Request body

json
{
  "token": "a1b2c3d4e5f6..."
}
FieldTypeRequiredDescription
tokenstringYesPlaintext bootstrap token (64 hex characters)

Response 200 OK

json
{
  "session_token": "f7e8d9c0b1a2...",
  "expires_at": 1738800000
}
FieldTypeDescription
session_tokenstringSetup session token for authenticating subsequent requests
expires_atintegerSession expiry as Unix epoch (seconds). Initial TTL is 30 minutes; renewed on each authenticated request.

Error responses

StatusCodeDescription
401invalid_tokenBootstrap token hash does not match
409already_configuredSetup is already complete
410token_consumedBootstrap token has already been used
410token_expiredBootstrap token TTL has elapsed
429too_many_attempts5 or more failed verification attempts
500no_bootstrap_tokenNo bootstrap token has been generated

Example

bash
curl -X POST http://127.0.0.1:8787/v1/setup/bootstrap-token/verify \
  -H "Content-Type: application/json" \
  -d '{"token": "a1b2c3d4e5f6..."}'

Save Setup Preferences

Persist setup-time access mode before owner creation.

POST /v1/setup/preferences

Authentication: Setup session token (Bearer)

Request body

json
{
  "runtime_mode": "remote",
  "remote_auth_mode": "trusted_proxy"
}

Response 200 OK

json
{
  "runtime_mode": "remote",
  "remote_auth_mode": "trusted_proxy",
  "session_expires_at": 1738801800
}

Error responses

StatusCodeDescription
401missing_authAuthorization header not provided
401invalid_sessionSetup session token is invalid
401session_expiredSetup session has expired
409already_configuredSetup is already complete
409invalid_stateOwner has already been created

Configure OIDC

Configure the OIDC identity provider. Performs provider discovery on the issuer URL and stores the configuration. If a client secret is provided, it is encrypted with AES-256-GCM before storage.

POST /v1/setup/oidc/configure

Authentication: Setup session token (Bearer)

State requirement: bootstrap_pending or idp_configured

Request body

json
{
  "issuer_url": "https://accounts.google.com",
  "client_id": "your-client-id.apps.googleusercontent.com",
  "client_secret": "GOCSPX-your-client-secret"
}
FieldTypeRequiredDescription
issuer_urlstringYesOIDC issuer URL (must support /.well-known/openid-configuration)
client_idstringYesOAuth 2.0 client ID from your identity provider
client_secretstringNoOAuth 2.0 client secret (encrypted at rest if provided)

Response 200 OK

json
{
  "state": "idp_configured",
  "discovered_issuer": "https://accounts.google.com",
  "session_expires_at": 1738801800
}
FieldTypeDescription
statestringNew setup state (idp_configured)
discovered_issuerstringIssuer URL as returned by the OIDC discovery document
session_expires_atinteger | nullUpdated session expiry (sliding window)

Error responses

StatusCodeDescription
400invalid_inputRequest body validation failed
400oidc_discovery_failedCould not fetch or parse the OIDC discovery document
401missing_authAuthorization header not provided
401invalid_sessionSetup session token is invalid
401session_expiredSetup session has expired
409already_configuredSetup is already complete
409invalid_stateNot in bootstrap_pending or idp_configured state
500encryption_errorFailed to encrypt client secret

Example

bash
curl -X POST http://127.0.0.1:8787/v1/setup/oidc/configure \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <session_token>" \
  -d '{
    "issuer_url": "https://accounts.google.com",
    "client_id": "your-client-id.apps.googleusercontent.com",
    "client_secret": "GOCSPX-your-client-secret"
  }'

Configure Trusted Proxy

Configure trusted-proxy auth during setup for runtime_mode=remote with remote_auth_mode=trusted_proxy.

POST /v1/setup/trusted-proxy/configure

Authentication: Setup session token (Bearer)

Request body

json
{
  "user_email_header": "x-warpgate-username",
  "trusted_proxy_cidrs": [],
  "shared_secret": "optional-shared-secret"
}
FieldTypeRequiredDescription
user_email_headerstringNoHeader containing the authenticated user email. Defaults to x-warpgate-username.
trusted_proxy_cidrsstring[]NoOptional allowlist of proxy source CIDRs.
shared_secretstringNoOptional write-only shared secret for defense in depth. When configured, the proxy must send it in X-Oore-Trusted-Proxy-Secret.

Response 200 OK

json
{
  "state": "idp_configured",
  "has_shared_secret": true,
  "configured_at": 1738800000,
  "session_expires_at": 1738801800
}

Error responses

StatusCodeDescription
400invalid_inputHeader name, CIDR list, or shared secret is invalid
401missing_authAuthorization header not provided
401invalid_sessionSetup session token is invalid
401session_expiredSetup session has expired
403mode_restrictedInstance is not in remote trusted-proxy setup mode
409already_configuredSetup is already complete
409invalid_stateOwner has already been created

Start Owner OIDC

Initiate an OIDC authorization code flow to verify the owner's identity. Returns an authorization URL to redirect the user to.

POST /v1/setup/owner/start-oidc

Authentication: Setup session token (Bearer)

State requirement: idp_configured only

Request body

json
{
  "redirect_uri": "http://127.0.0.1:4173/auth/callback"
}
FieldTypeRequiredDescription
redirect_uristringYesURI where the IdP should redirect after authentication

Response 200 OK

json
{
  "authorization_url": "https://accounts.google.com/o/oauth2/v2/auth?client_id=...&redirect_uri=...&state=...&nonce=...",
  "state": "abc123-csrf-state-token"
}
FieldTypeDescription
authorization_urlstringFull authorization URL to redirect the user to
statestringCSRF state token for validating the callback

The daemon generates a PKCE challenge (S256), CSRF state token, and nonce internally. The PKCE verifier and nonce are stored server-side, keyed by the state value. Pending auth entries expire after 10 minutes.

Error responses

StatusCodeDescription
400invalid_redirect_uriThe redirect URI is malformed
401missing_authAuthorization header not provided
401invalid_sessionSetup session token is invalid
401session_expiredSetup session has expired
409already_configuredSetup is already complete
409invalid_stateNot in idp_configured state
429too_many_pendingToo many pending auth requests (limit: 1000)
502oidc_discovery_errorFailed to perform OIDC discovery

Example

bash
curl -X POST http://127.0.0.1:8787/v1/setup/owner/start-oidc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <session_token>" \
  -d '{"redirect_uri": "http://127.0.0.1:4173/auth/callback"}'

Claim Owner From Trusted Proxy

Create the owner record from the identity asserted by the trusted upstream proxy.

POST /v1/setup/owner/claim-trusted-proxy

Authentication: Setup session token (Bearer)

Request body

None.

Required proxy headers

By default, the request must include:

text
X-Warpgate-Username: owner@example.com

If a trusted-proxy shared secret is configured, the request must also include:

text
X-Oore-Trusted-Proxy-Secret: configured-shared-secret

Response 200 OK

json
{
  "state": "owner_created",
  "owner_email": "owner@example.com",
  "session_expires_at": 1738801800
}

Error responses

StatusCodeDescription
401missing_authAuthorization header not provided
401invalid_sessionSetup session token is invalid
401session_expiredSetup session has expired
401trusted_proxy_shared_secret_missingTrusted proxy shared secret header is required but missing
401trusted_proxy_shared_secret_invalidTrusted proxy shared secret header does not match
403mode_restrictedInstance is not in trusted-proxy setup mode
403trusted_proxy_peer_not_allowedRequest did not come from a trusted proxy peer
401trusted_proxy_identity_missingTrusted proxy identity header is missing
401trusted_proxy_identity_invalidTrusted proxy identity header is not a valid email
409trusted_proxy_not_configuredTrusted proxy settings have not been configured yet
409invalid_stateNot in idp_configured state

Create Local Owner

Create the owner record directly when setup is running in runtime_mode=local.

POST /v1/setup/local-owner/create

Authentication: Setup session token (Bearer)

Request body

json
{
  "email": "owner@local"
}

Response 200 OK

json
{
  "state": "owner_created",
  "owner_email": "owner@local",
  "session_expires_at": 1738801800
}

Error responses

StatusCodeDescription
400invalid_inputEmail is invalid
401missing_authAuthorization header not provided
401invalid_sessionSetup session token is invalid
401session_expiredSetup session has expired
403mode_restrictedLocal owner creation is only available in local mode
409invalid_stateNot in the local owner-creation state

Verify Owner OIDC

Complete the OIDC authorization code flow started by Start Owner OIDC. Exchanges the authorization code for tokens, verifies the ID token, extracts the owner's email and OIDC subject, and creates the owner record.

POST /v1/setup/owner/verify-oidc

Authentication: Setup session token (Bearer)

State requirement: idp_configured only

Request body

json
{
  "code": "4/0AX4XfWh...",
  "state": "abc123-csrf-state-token"
}
FieldTypeRequiredDescription
codestringYesAuthorization code from the IdP callback
statestringYesCSRF state token from the IdP callback (must match the value from start-oidc)

Response 200 OK

json
{
  "state": "owner_created",
  "owner_email": "admin@example.com",
  "oidc_subject": "110123456789012345678",
  "session_expires_at": 1738801800
}
FieldTypeDescription
statestringNew setup state (owner_created)
owner_emailstringEmail address extracted from the ID token
oidc_subjectstringOIDC subject identifier from the ID token
session_expires_atinteger | nullUpdated session expiry (sliding window)

Error responses

StatusCodeDescription
400invalid_stateUnknown or expired OIDC state parameter
400auth_expiredOIDC authorization request has expired (10-minute TTL)
401missing_authAuthorization header not provided
401invalid_sessionSetup session token is invalid
401session_expiredSetup session has expired
409already_configuredSetup is already complete
409invalid_stateNot in idp_configured state
500decryption_errorFailed to decrypt stored client secret
500store_errorDatabase operation failed
502oidc_discovery_errorFailed to perform OIDC discovery
502token_exchange_errorFailed to exchange authorization code for tokens
502missing_id_tokenIdP did not return an ID token
502id_token_verification_errorID token signature or claims verification failed
502missing_emailID token does not contain an email claim

Example

bash
curl -X POST http://127.0.0.1:8787/v1/setup/owner/verify-oidc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <session_token>" \
  -d '{
    "code": "4/0AX4XfWh...",
    "state": "abc123-csrf-state-token"
  }'

Complete Setup

Finalize the setup process. Transitions the instance to ready state, clears the setup session, and permanently disables all setup endpoints.

POST /v1/setup/complete

Authentication: Setup session token (Bearer)

State requirement: owner_created only

Request body

None.

Response 200 OK

json
{
  "state": "ready",
  "instance_id": "550e8400-e29b-41d4-a716-446655440000"
}
FieldTypeDescription
statestringFinal setup state (ready)
instance_idstringUUID of the configured instance

Error responses

StatusCodeDescription
401missing_authAuthorization header not provided
401invalid_sessionSetup session token is invalid
401session_expiredSetup session has expired
409already_configuredSetup is already complete
409invalid_stateNot in owner_created state

Example

bash
curl -X POST http://127.0.0.1:8787/v1/setup/complete \
  -H "Authorization: Bearer <session_token>"

DANGER

This action is irreversible. Once setup is complete, all setup endpoints are permanently disabled.

Self-hosted mobile CI, built for Flutter.