Skip to content

Two-Factor Authentication (2FA)

Knosc supports TOTP-based two-factor authentication (compatible with Google Authenticator, Authy, 1Password, etc.).


Setup: Generate Secret

POST /api/setup-2fa/generate

Authentication required. CSRF header required: X-XSRF-TOKEN

Generates a new 2FA secret and returns a QR code for scanning with an authenticator app.

Response

{
  "secret": "BASE32ENCODEDSECRET",
  "qr_code": "data:image/png;base64,<base64-encoded-image>"
}
Field Type Description
secret string Base32-encoded TOTP secret for manual entry
qr_code string Base64-encoded QR code image (data URI)

Setup: Activate 2FA

POST /api/setup-2fa/activate

Authentication required. CSRF header required: X-XSRF-TOKEN

Confirms that the user has successfully scanned the QR code by verifying the first TOTP code. 2FA is only enabled after this call succeeds.

Request Body

{
  "totp_code": "123456"
}
Field Type Required Description
totp_code string Yes 6-digit TOTP code from the authenticator app

Response - Success

{
  "message": "Two-factor authentication enabled."
}

Response - Invalid Code

HTTP/1.1 400 Bad Request

{
  "Message": "Invalid TOTP code.",
  "Code": "2FA.InvalidCode"
}

Login: Verify 2FA Code

POST /api/verify-2fa

Public endpoint. Called after a login attempt that returns {"requires_2fa": true}.

Request Body

{
  "username": "jane.doe@acme.com",
  "totp_code": "123456"
}
Field Type Required Description
username string Yes The username used in the initial login attempt
totp_code string Yes Current 6-digit TOTP code

Response - Success

HTTP/1.1 200 OK
Set-Cookie: access_token_cookie=<jwt>; HttpOnly; SameSite=Lax; Path=/
Set-Cookie: csrf_access_token=<token>; SameSite=Lax; Path=/

{
  "login": true
}

Response - Invalid Code

HTTP/1.1 401 Unauthorized

{
  "Message": "Invalid or expired TOTP code.",
  "Code": "2FA.InvalidCode"
}

Admin: Reset User 2FA

POST /api/user/{user_id}/reset-2fa

Required role: Administrator CSRF header required: X-XSRF-TOKEN

Disables 2FA for the specified user. The user will be prompted to set up 2FA again on next login if 2FA is required by policy.

Path Parameters

Parameter Type Required Description
user_id integer Yes Internal user identifier

Response

{
  "message": "2FA has been reset for the user."
}

2FA Login Flow

1. POST /api/authenticate        →  {"requires_2fa": true}
2. User opens authenticator app
3. POST /api/verify-2fa          →  {"login": true} + session cookies
4. Normal API usage begins

Code Example

import requests

BASE = "https://acme.knosc.com"
session = requests.Session()

# Step 1 - Initial login
r = session.post(f"{BASE}/api/authenticate", json={
    "username": "jane.doe@acme.com",
    "password": "your-password"
})
body = r.json()

if body.get("requires_2fa"):
    # Step 2 - Provide TOTP code
    totp_code = input("Enter 2FA code: ")
    r = session.post(f"{BASE}/api/verify-2fa", json={
        "username": "jane.doe@acme.com",
        "totp_code": totp_code
    })
    assert r.json().get("login"), "2FA verification failed"

elif body.get("login"):
    pass  # No 2FA, already logged in