============== Authentication ============== CorePlexML uses session cookies for web UI access and Bearer tokens (API keys) for programmatic access. Public endpoints that do **not** require authentication are: ``POST /api/auth/register``, ``POST /api/auth/login``, ``POST /api/auth/forgot-password``, ``POST /api/auth/reset-password``, and ``GET /api/auth/verify-email``. .. important:: API key management endpoints (``/api/auth/api-keys*``) require **cookie session authentication**. They do not accept Bearer API keys. For cookie-authenticated ``POST``/``PUT``/``PATCH``/``DELETE`` requests, include ``X-CSRF-Token`` with the value from the ``csrf_token`` cookie. .. contents:: Endpoints :local: :depth: 1 ---- Register User ------------- .. code-block:: text POST /api/auth/register Create a new user account. **Request Body** .. list-table:: :header-rows: 1 :widths: 20 10 10 60 * - Field - Type - Required - Description * - ``email`` - string - Yes - Valid email address. * - ``name`` - string - Yes - Display name. * - ``password`` - string - Yes - Minimum 8 characters. **Example** .. code-block:: bash curl -X POST "$BASE_URL/api/auth/register" \ -H "Content-Type: application/json" \ -d '{ "email": "alice@example.com", "name": "Alice Chen", "password": "s3cure!Pass" }' .. code-block:: python import requests resp = requests.post(f"{BASE_URL}/api/auth/register", json={ "email": "alice@example.com", "name": "Alice Chen", "password": "s3cure!Pass", }) print(resp.json()) **Response** ``201 Created`` .. code-block:: json { "user": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "email": "alice@example.com", "name": "Alice Chen" }, "verification_required": true } New accounts must verify email before they can log in. ---- Login ----- .. code-block:: text POST /api/auth/login Authenticate and receive a session cookie. **Request Body** .. list-table:: :header-rows: 1 :widths: 20 10 10 60 * - Field - Type - Required - Description * - ``email`` - string - Yes - Registered email. * - ``password`` - string - Yes - Account password. * - ``remember`` - boolean - No - Extend session duration (default ``false``). **Example** .. code-block:: bash curl -X POST "$BASE_URL/api/auth/login" \ -H "Content-Type: application/json" \ -c cookies.txt \ -d '{ "email": "alice@example.com", "password": "s3cure!Pass" }' .. code-block:: python session = requests.Session() resp = session.post(f"{BASE_URL}/api/auth/login", json={ "email": "alice@example.com", "password": "s3cure!Pass", }) # session object now carries the cookie for subsequent requests **Response** ``200 OK`` .. code-block:: json { "user": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "email": "alice@example.com", "name": "Alice Chen" } } The response also sets an ``HttpOnly`` session cookie. If the email is not verified, login returns ``403`` with detail: ``Email not verified. Please check your inbox for the activation link.``. ---- Logout ------ .. code-block:: text POST /api/auth/logout Revoke the current session. **Example** .. code-block:: bash curl -X POST "$BASE_URL/api/auth/logout" \ -b cookies.txt **Response** ``200 OK`` .. code-block:: json { "ok": true } ---- Get Current User ---------------- .. code-block:: text GET /api/auth/me Return profile information for the authenticated user. **Example** .. code-block:: bash curl "$BASE_URL/api/auth/me" \ -H "Authorization: Bearer YOUR_API_KEY" .. code-block:: python resp = requests.get(f"{BASE_URL}/api/auth/me", headers={ "Authorization": "Bearer YOUR_API_KEY", }) user = resp.json() **Response** ``200 OK`` .. code-block:: json { "user": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "email": "alice@example.com", "name": "Alice Chen", "is_superuser": false, "email_verified_at": "2026-01-15T10:30:00Z" } } ---- Create API Key -------------- .. code-block:: text POST /api/auth/api-keys Generate a new API key for programmatic access. The secret is returned **only once** in the response -- store it securely. **Request Body** .. list-table:: :header-rows: 1 :widths: 20 10 10 60 * - Field - Type - Required - Description * - ``name`` - string - Yes - Human-readable label for the key. * - ``scopes`` - array[string] - No - Permissions: ``read``, ``write``, ``predict``, ``admin``. Default: all. **Example** .. code-block:: bash # Requires a cookie-authenticated session and CSRF token curl -X POST "$BASE_URL/api/auth/api-keys" \ -b cookies.txt \ -H "X-CSRF-Token: " \ -H "Content-Type: application/json" \ -d '{ "name": "CI Pipeline Key", "scopes": ["*"] }' .. code-block:: python csrf = session.cookies.get("csrf_token") resp = session.post(f"{BASE_URL}/api/auth/api-keys", headers={ "X-CSRF-Token": csrf, }, json={ "name": "CI Pipeline Key", "scopes": ["*"], }) key_data = resp.json() print("Save this key:", key_data["api_key"]) **Response** ``201 Created`` .. code-block:: json { "prefix": "cp_a1b2c3d4", "api_key": "cp_a1b2c3d4.", "scopes": ["*"] } .. warning:: The ``key`` field is shown only in this response. If lost you must revoke the key and create a new one. ---- List API Keys ------------- .. code-block:: text GET /api/auth/api-keys Return all API keys for the current user. The secret portion of each key is **not** included. **Example** .. code-block:: bash curl "$BASE_URL/api/auth/api-keys" \ -b cookies.txt **Response** ``200 OK`` .. code-block:: json [ { "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", "name": "CI Pipeline Key", "prefix": "cp_a1b2c3d4", "scopes": ["*"], "last_used_at": "2026-02-28T18:45:00Z", "created_at": "2026-02-28T14:00:00Z" } ] ---- Revoke API Key -------------- .. code-block:: text POST /api/auth/api-keys/{key_id}/revoke Permanently revoke an API key. Subsequent requests using that key will return ``401 Unauthorized``. **Path Parameters** .. list-table:: :header-rows: 1 :widths: 20 10 70 * - Parameter - Type - Description * - ``key_id`` - UUID - The ID of the API key to revoke. **Example** .. code-block:: bash curl -X POST "$BASE_URL/api/auth/api-keys/b2c3d4e5-f6a7-8901-bcde-f12345678901/revoke" \ -b cookies.txt \ -H "X-CSRF-Token: " **Response** ``200 OK`` .. code-block:: json { "ok": true } ---- Forgot Password --------------- .. code-block:: text POST /api/auth/forgot-password Request a password reset email. Always returns ``200`` regardless of whether the email exists to prevent account enumeration. **Request Body** .. list-table:: :header-rows: 1 :widths: 20 10 10 60 * - Field - Type - Required - Description * - ``email`` - string - Yes - The email address associated with the account. **Example** .. code-block:: bash curl -X POST "$BASE_URL/api/auth/forgot-password" \ -H "Content-Type: application/json" \ -d '{"email": "alice@example.com"}' **Response** ``200 OK`` .. code-block:: json { "ok": true } ---- Reset Password -------------- .. code-block:: text POST /api/auth/reset-password Set a new password using a reset token received by email. **Request Body** .. list-table:: :header-rows: 1 :widths: 20 10 10 60 * - Field - Type - Required - Description * - ``token`` - string - Yes - Reset token from the email link (minimum 10 characters). * - ``password`` - string - Yes - New password (minimum 8 characters). **Example** .. code-block:: bash curl -X POST "$BASE_URL/api/auth/reset-password" \ -H "Content-Type: application/json" \ -d '{ "token": "abc123def456ghi789jkl012mno345", "password": "newS3cure!Pass" }' **Response** ``200 OK`` .. code-block:: json { "ok": true } ---- .. seealso:: - :doc:`errors` -- Error codes returned by auth endpoints (``401``, ``403``, ``429``). - :doc:`projects` -- Creating projects after authentication.