JSON Authentication

Devise API docs.

Use the same Devise-backed users through browser pages or JSON endpoints. API requests authenticate with 5-minute JWT bearer tokens, and refresh tokens rotate whenever they are used.

Bearer Token Quick Start

Get a JWT bearer token from registration or login.

The API returns a JWT in the top-level access_token field. Store the refresh token securely, use the access token as Authorization: Bearer <jwt>, and refresh it before the 5-minute expiry.

1 POST

Register a new API user

/api/v1/auth/registration

Use this when the client needs to create an account and start an authenticated session immediately.

curl

Copy and run this command

curl -X POST https://einram.com/api/v1/auth/registration \
  -H "Content-Type: application/json" \
  -d '{
    "user": {
      "first_name": "Marnie",
      "last_name": "Paraiso",
      "email": "developer@example.com",
      "password": "secure-password-123",
      "password_confirmation": "secure-password-123"
    }
  }'
2 POST

Log in an existing user

/api/v1/auth/session

Use this when the user already has an account. A successful login returns a fresh JWT access token and refresh token.

curl

Copy and run this command

curl -X POST https://einram.com/api/v1/auth/session \
  -H "Content-Type: application/json" \
  -d '{"user":{"email":"developer@example.com","password":"secure-password-123"}}'
3 GET

Send the access token on protected requests

/api/v1/auth/session

Copy the response `access_token` value and pass it in the Authorization header for current-user and logout requests.

curl

Copy and run this command

curl https://einram.com/api/v1/auth/session \
  -H "Authorization: Bearer <jwt-access-token>"
4 POST

Refresh before the access token expires

/api/v1/auth/session/refresh

Send the refresh token to receive a new 5-minute JWT and a replacement refresh token. The previous refresh token is revoked.

curl

Copy and run this command

curl -X POST https://einram.com/api/v1/auth/session/refresh \
  -H "Content-Type: application/json" \
  -d '{"refresh_token":"<refresh-token>"}'
POST /api/v1/auth/registration 201 Created

Create account

Creates an active Devise user and returns a short-lived JWT access token plus a refresh token.

Request

application/json

{
  "user": {
    "first_name": "Marnie",
    "middle_name": "Santos",
    "last_name": "Paraiso",
    "email": "developer@example.com",
    "password": "secure-password-123",
    "password_confirmation": "secure-password-123"
  }
}

Response

JSON / status body

{
  "access_token": "<jwt-access-token>",
  "token_type": "Bearer",
  "expires_in": 300,
  "expires_at": "2026-07-15T14:25:00.000Z",
  "refresh_token": "<refresh-token>",
  "user": {
    "id": 1,
    "email": "developer@example.com",
    "first_name": "Marnie",
    "middle_name": "Santos",
    "last_name": "Paraiso",
    "status": "active",
    "last_api_sign_in_at": "2026-07-15T14:20:00.000Z"
  }
}
POST /api/v1/auth/session 200 OK

Log in

Authenticates with Devise password validation and returns a JWT access token plus a refresh token.

Request

application/json

{
  "user": {
    "email": "developer@example.com",
    "password": "secure-password-123"
  }
}

Response

JSON / status body

{
  "access_token": "<jwt-access-token>",
  "token_type": "Bearer",
  "expires_in": 300,
  "expires_at": "2026-07-15T14:30:00.000Z",
  "refresh_token": "<refresh-token>",
  "user": {
    "id": 1,
    "email": "developer@example.com",
    "first_name": "Marnie",
    "middle_name": "Santos",
    "last_name": "Paraiso",
    "status": "active",
    "last_api_sign_in_at": "2026-07-15T14:25:00.000Z"
  }
}
POST /api/v1/auth/session/refresh 200 OK

Refresh tokens

Rotates a valid refresh token and returns a new 5-minute JWT access token plus a replacement refresh token.

Request

application/json

{
  "refresh_token": "<refresh-token>"
}

Response

JSON / status body

{
  "access_token": "<new-jwt-access-token>",
  "token_type": "Bearer",
  "expires_in": 300,
  "expires_at": "2026-07-15T14:35:00.000Z",
  "refresh_token": "<new-refresh-token>",
  "user": {
    "id": 1,
    "email": "developer@example.com",
    "first_name": "Marnie",
    "middle_name": "Santos",
    "last_name": "Paraiso",
    "status": "active",
    "last_api_sign_in_at": "2026-07-15T14:30:00.000Z"
  }
}
GET /api/v1/auth/session 200 OK

Current user

Returns the user for a valid, unexpired JWT access token.

Request

application/json

Authorization: Bearer <jwt-access-token>

Response

JSON / status body

{
  "user": {
    "id": 1,
    "email": "developer@example.com",
    "first_name": "Marnie",
    "middle_name": "Santos",
    "last_name": "Paraiso",
    "status": "active",
    "last_api_sign_in_at": "2026-07-15T14:25:00.000Z"
  }
}
DELETE /api/v1/auth/session 204 No Content

Log out

Revokes active refresh tokens for the current JWT-authenticated user.

Request

application/json

Authorization: Bearer <jwt-access-token>

Response

JSON / status body

No response body.

User Table Contract

Custom and authentication fields.

users
id integer Response only Database id for the user.
first_name string Required on registration; returned Custom user profile field.
middle_name string Optional on registration; returned Custom user profile field. May be null or blank.
last_name string Required on registration; returned Custom user profile field.
email string Required on registration and login; returned Devise authentication email.
password string Required on registration and login; never returned Plain password accepted only in request payloads.
password_confirmation string Required on registration; never returned Must match password when creating an account.
status string Response only Account access state. Allowed values: active, inactive, banned, suspended.
last_api_sign_in_at datetime Response only Most recent successful API login timestamp.
access_token JWT string Returned on registration, login, and refresh Short-lived bearer token. It expires after 5 minutes.
refresh_token string Returned on registration, login, and refresh Longer-lived token used only to request a new access token.
token_digest string Internal only Stored SHA256 refresh-token digest. It is never returned by the API.

JWT access tokens expire after 5 minutes. Refresh tokens are stored only as SHA256 digests, and each refresh request revokes the old refresh token before returning a replacement.

HTTPS

Production forces SSL so access and refresh tokens are sent only over HTTPS.

Rate limiter

10 /api/v1/auth/* requests per IP per minute. Limited clients receive 429 with Retry-After and X-RateLimit headers.

Blocked accounts

inactive, banned, and suspended users receive 403 and no tokens.

Invalid tokens

Missing, expired, malformed, or tampered JWT bearer tokens receive 401.