Skip to content

Authentication API

All endpoints are prefixed with {BASE_PATH} — default /api. Authentication endpoints are public (no JWT required), except where noted.

Base URL: https://api.hule-do.com/api (production)

Token-based auth

Hule uses JWT access tokens (Bearer) for API authentication.

  • Access token: short-lived (default 15 minutes). Sent in the Authorization: Bearer <token> header.
  • Refresh token: long-lived (default 30 days). Used to obtain a new access token.
  • Refresh tokens are single-use and rotated on every refresh. Reusing an old refresh token revokes all sessions for that user.

All authenticated endpoints return 401 Unauthorized if the token is missing or expired.


POST /auth/register

Create a signup request. A confirmation email is sent — the account is created only after confirmation.

Request:

json
{
  "email": "user@example.com",
  "password": "securePassword123",
  "name": "Alex"
}

Response: 201 — no body (confirmation link sent to email).


POST /auth/register/confirm

Confirm registration with the token from the email.

Request:

json
{
  "token": "abc123..."
}

Response: 201

json
{
  "accessToken": "eyJhbG...",
  "refreshToken": "dGhpcyBp...",
  "user": {
    "id": "667f...",
    "email": "user@example.com",
    "name": "Alex"
  }
}

Account is created with isEmailVerified: true. A default workspace is created automatically.


POST /auth/login

Login with email and password.

Request:

json
{
  "email": "user@example.com",
  "password": "securePassword123"
}

Response: 200

json
{
  "accessToken": "eyJhbG...",
  "refreshToken": "dGhpcyBp...",
  "user": { "id": "...", "email": "...", "name": "..." }
}

POST /auth/login/code

Request a one-time login code sent to your email. Works for any registered email — no password needed.

Request:

json
{
  "email": "user@example.com"
}

Response: 200 — code sent to email (valid for 10 minutes, 5 attempts).


POST /auth/login/code/confirm

Exchange the login code for tokens.

Request:

json
{
  "email": "user@example.com",
  "code": "482913"
}

Response: 200

json
{
  "accessToken": "eyJhbG...",
  "refreshToken": "dGhpcyBp...",
  "user": { "id": "...", "email": "...", "name": "..." }
}

POST /auth/login/google

Login or register with a Google ID token.

Request:

json
{
  "idToken": "eyJhbGciOiJSUzI1NiIs..."
}

Response: 200

json
{
  "accessToken": "eyJhbG...",
  "refreshToken": "dGhpcyBp...",
  "user": { "id": "...", "email": "...", "name": "..." }
}

POST /auth/refresh

Exchange a refresh token for a new access token and a new refresh token.

Request:

json
{
  "refreshToken": "dGhpcyBp..."
}

Response: 200

json
{
  "accessToken": "eyJhbG...",
  "refreshToken": "bmV3IHJl..."
}

POST /auth/logout

Revoke the current refresh token. Requires authentication (Bearer token).

Headers: Authorization: Bearer <accessToken>

Request:

json
{
  "refreshToken": "dGhpcyBp..."
}

Response: 204 No Content


POST /auth/password/reset/request

Request a password reset email.

Request:

json
{
  "email": "user@example.com"
}

Response: 200 — reset link sent to email.


POST /auth/password/reset/confirm

Reset the password using the token from the email. All existing sessions are invalidated.

Request:

json
{
  "token": "abc123...",
  "newPassword": "newSecurePassword456"
}

Response: 204 No Content


POST /auth/email/change/request

Request an email change. Requires authentication.

Headers: Authorization: Bearer <accessToken>

Request:

json
{
  "newEmail": "newemail@example.com"
}

Response: 200 — confirmation link sent to new email.


POST /auth/email/change/confirm

Confirm email change with the token.

Request:

json
{
  "token": "abc123..."
}

Response: 204 No Content


DELETE /auth/me

Delete your account permanently. Requires authentication.

Headers: Authorization: Bearer <accessToken>

Request:

json
{
  "password": "myPassword"
}

For passwordless accounts (Google/Telegram), send "email": "user@example.com" instead.

Response: 204 No Content


GET /account/export

Export all your data (GDPR Art. 20). Requires authentication. Rate-limited (heavier than normal reads).

Headers: Authorization: Bearer <accessToken>

Response: 200 — full JSON export of profile, owned workspaces, and notifications.


Error responses

All endpoints return errors in a consistent format:

json
{
  "error": "ValidationError",
  "issues": [
    { "path": "email", "message": "email must be a valid email address" }
  ]
}

Common HTTP status codes:

CodeMeaning
400Bad request — invalid input
401Unauthorised — missing or invalid token
403Forbidden — insufficient permissions
404Not found
429Too many requests — rate limit exceeded
500Internal server error