• English
  • Authenticate and Authorize All Requests to the Octop API

    Every Octop API call — except /api/health, /api/setup/*, /api/auth/captcha, public SSO start/callback/exchange routes, invite redeem, and the OpenAPI schema — requires a JWT access token. Obtain the token by logging in with your credentials, then include it in the Authorization header of every subsequent request. Tokens expire after 24 hours by default; re-login to get a fresh one.

    WARNING

    First-run credentials depend on how you installed Octop. After a bare-metal octop init / setup wizard, open ~/octop-login.txt for the one-time setup password, then sign in with the admin username and password you created. After Docker first boot, sign in as admin (or OCTOP_ADMIN_USERNAME) with the password in /data/.octop/credential.txt (docker exec octop cat /data/.octop/credential.txt). Octop generates a random password unless you set OCTOP_DEFAULT_PASSWORD; weak values fall back to a random password. Use those credentials for API login.

    Log in and get a token

    POST your credentials

    Send your username and password to the login endpoint:

    cURL
    Python
    cURL
    curl -X POST http://127.0.0.1:8088/api/auth/login \
      -H 'Content-Type: application/json' \
      -d '{"username": "<your_username>", "password": "<your_password>"}'

    Extract the access token

    The response body contains your JWT token along with your role and user details:

    {
      "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
      "role": "admin",
      "user": {
        "id": 1,
        "username": "admin",
        "display_name": "Administrator"
      }
    }

    Pass the token in the Authorization header

    Include the token as a Bearer credential on every subsequent request:

    cURL
    Python
    cURL
    curl http://127.0.0.1:8088/api/agents \
      -H 'Authorization: Bearer <your_token>'

    Login request fields

    usernamestringbodyrequired

    The account username you created during the setup wizard (or later via user management).

    passwordstringbodyrequired

    The account password you set during the setup wizard (or later via password reset).

    captcha_tokenstringbody

    Required when a strong captcha provider is active (turnstile, hcaptcha, recaptcha, recaptcha-v3, or tencent). Maximum 4096 characters. For tencent, send the callback pair as ticket:randstr. The default slider is dashboard-only and is not checked here.

    Login response fields

    access_tokenstring

    A signed JWT token. Include this value as Bearer <access_token> in the Authorization header.

    rolestring

    The account's role. Either "admin" or "user".

    userobject

    Basic profile information for the authenticated account.

    user fields
    user.idinteger

    Unique numeric identifier for the user.

    user.usernamestring

    The account's login username.

    user.display_namestring

    The human-readable display name shown in the web UI.

    Token expiry

    Tokens expire after 24 hours by default. Control this with the OCTOP_ACCESS_TOKEN_TTL environment variable (value in seconds). When a token expires, re-call POST /api/auth/login to obtain a fresh one.

    NOTE

    Rotating the JWT secret via octop admin rotate-jwt-secret immediately invalidates all outstanding tokens. Every user must re-login after a rotation.

    Get current user info

    Retrieve the profile of the currently authenticated user:

    curl http://127.0.0.1:8088/api/auth/me \
      -H 'Authorization: Bearer <token>'

    The response includes id, username, role, display_name, locale, plus SSO fields: sso_identities (linked {kind} rows), sso_linked, sso_kind (first linked kind), and has_password.

    Change password

    Update your own password without admin involvement:

    curl -X POST http://127.0.0.1:8088/api/auth/change-password \
      -H 'Authorization: Bearer <token>' \
      -H 'Content-Type: application/json' \
      -d '{"old_password": "octop", "new_password": "mysecurepass1"}'

    A successful response returns 204 No Content.

    New passwords must be at least 8 characters, include a letter and a digit, differ from the current password, and must not be on a small denylist of common strings (for example password123 or admin123).

    Login captcha

    GET /api/auth/captcha returns {provider, site_key?} for the login widget. It is public, and returns 503 while first-run setup is still required. Default provider is slider (dashboard only; the API does not verify a token).

    When a strong provider is active, POST /api/auth/login must include captcha_token. Captcha failures do not increment login lockout. OIDC and OAuth login skip this check.

    Configure the provider under Management → App settings, or with OCTOP_CAPTCHA_* (boot snapshot; restart after you change env). GET / PUT /api/settings/captcha require the captcha permission. Secrets are omitted from GET; sending an empty secret on PUT keeps the stored value.

    If a settings-sourced strong provider locks everyone out, run octop captcha reset and restart octop run. If boot env (OCTOP_CAPTCHA_*) is the cause, edit ~/.octop/env on disk — the dashboard is unreachable until the process starts.

    Single sign-on

    An administrator enables SSO under Management → Users → Single sign-on. After at least one user exists, the login page can show Continue with {name} for each enabled provider.

    OpenID Connect

    The web UI includes quick-start presets for Azure AD, Google, Keycloak, and Okta. Pick a preset to fill common scopes, enter the issuer URL and OAuth client credentials, then copy the generated redirect URI into your identity provider. Save before you click Test connection; Octop tests the saved discovery settings.

    MethodPathWho can call itWhat it does
    GET/auth/oidc/statusanyoneWhether SSO is on, and the button label
    POST/auth/oidc/startanyoneStart the identity-provider login
    GET/auth/oidc/callbackanyoneReturn from the identity provider
    POST/auth/oidc/exchangeanyoneFinish login and return the same JWT as password login
    GET/auth/oidc/configadminRead SSO settings (secret is hidden)
    PUT/auth/oidc/configadminSave SSO settings
    POST/auth/oidc/config/testadminTest that the provider is reachable

    Feishu, DingTalk, and WeCom

    The same Single sign-on panel also configures Feishu, DingTalk, and WeCom. Enter the OAuth client id and secret, copy the generated callback URL into the provider console, then save and Test connection. WeCom also needs extra.agent_id.

    A signed-in user can bind or unbind these identities. Unbinding the last login method requires a local password.

    MethodPathWho can call itWhat it does
    GET/auth/oauth/statusanyone{providers:[{kind, display_name, enabled}]}
    POST/auth/oauth/startanyoneBody {kind, redirect_after?} → authorization URL (kind is oidc, feishu, dingtalk, or wecom)
    GET/auth/oauth/callbackanyoneProvider callback (code, or DingTalk authCode)
    POST/auth/oauth/exchangeanyoneSame one-time code exchange as /auth/oidc/exchange
    POST/auth/oauth/bind/startuserBind the identity to the current user
    POST/auth/oauth/unbinduserUnlink one SSO identity by kind
    GET/auth/oauth/providers/{kind}ssoProvider config; client_secret is omitted
    PUT/auth/oauth/providers/{kind}ssoUpsert provider config; client_secret is write-only
    POST/auth/oauth/providers/{kind}/testssoTest provider credentials

    New SSO users get a regular user account. Grant settings access afterwards if they need it. The older /auth/oidc/config routes still work for the OIDC provider.

    Redeem an invite

    Anyone with an invite link can call these routes. Administrators create invites from Management → Users or POST /api/users/invites. See Users & Admin.

    MethodPathWhat it does
    POST/auth/invite/validateCheck that a code is still valid
    POST/auth/invite/redeemCreate the user and return a JWT

    Log out

    Invalidate the current token server-side:

    curl -X POST http://127.0.0.1:8088/api/auth/logout \
      -H 'Authorization: Bearer <token>'

    A successful response returns 204 No Content.

    Error reference

    HTTP StatusError CodeCauseResolution
    401 UnauthorizedAUTH_FAILEDInvalid credentials supplied at loginCheck username and password
    401 UnauthorizedTOKEN_EXPIREDJWT has passed its TTLRe-login to obtain a fresh token
    403 ForbiddenFORBIDDENAuthenticated but insufficient role (e.g., non-admin accessing an admin endpoint)Log in with an account that has the required role
    403 ForbiddenUSER_DISABLEDThe account has been disabled by an adminContact your Octop administrator
    423 LockedLOGIN_LOCKEDToo many failed login attempts; account is lockedWait out the lockout period, or ask an admin to call POST /api/users/{id}/unlock-login
    TIP

    Set OCTOP_ENABLE_API_DOCS=1 (or "enable_api_docs": true in config.json) and visit http://127.0.0.1:8088/api/docs to explore every endpoint interactively with the built-in Scalar interface — no extra tooling required.