Skip to main content
The Bloom Housing API uses JWT tokens for authentication. Tokens are issued as HTTP-only cookies on login and must be present on subsequent requests to protected endpoints.

How it works

When you log in, the API sets two cookies on the response:
CookieDescription
access-tokenShort-lived JWT used to authenticate requests. Valid for 1 hour.
refresh-tokenLonger-lived token used to obtain a new access token without re-entering credentials.
Because tokens are stored in HTTP-only cookies, your HTTP client must send cookies with every request (e.g., credentials: 'include' in fetch, or withCredentials: true in Axios).

Login

1

POST /auth/login

Send your email and password as JSON.
curl -X POST http://localhost:3100/auth/login \
  -H 'Content-Type: application/json' \
  -c cookies.txt \
  -d '{"email": "user@example.com", "password": "yourpassword"}'
On success, the server sets access-token and refresh-token cookies and returns:
{ "success": true }
2

Use the access-token cookie on subsequent requests

Your HTTP client will automatically send the cookie with each subsequent request if cookie handling is enabled.
curl http://localhost:3100/user \
  -b cookies.txt

Multi-factor authentication (MFA)

MFA can be enabled per jurisdiction. When it is active, the login process requires a second step.
1

Request an MFA code

Call POST /auth/request-mfa-code with your email and password. This triggers a code to be sent via email or SMS (via Twilio).
curl -X POST http://localhost:3100/auth/request-mfa-code \
  -H 'Content-Type: application/json' \
  -d '{"email": "user@example.com", "password": "yourpassword", "mfaType": "email"}'
2

Log in with the MFA code

Include mfaCode in your login request body.
curl -X POST http://localhost:3100/auth/login \
  -H 'Content-Type: application/json' \
  -c cookies.txt \
  -d '{"email": "user@example.com", "password": "yourpassword", "mfaCode": "123456"}'

Single-use code login

When the enableSingleUseCode feature flag is active for a jurisdiction, users can log in with a one-time code instead of a password.
# Request a single-use code
curl -X POST http://localhost:3100/user/request-single-use-code \
  -H 'Content-Type: application/json' \
  -d '{"email": "user@example.com"}'

# Log in using the code
curl -X POST http://localhost:3100/auth/loginViaSingleUseCode \
  -H 'Content-Type: application/json' \
  -c cookies.txt \
  -d '{"email": "user@example.com", "singleUseCode": "123456"}'

Refreshing an access token

The access token expires after 1 hour. Use the refresh token to obtain a new one without requiring the user to log in again.
curl -X GET http://localhost:3100/auth/requestNewToken \
  -b cookies.txt \
  -c cookies.txt
If the refresh token is valid, the server issues a new access-token cookie. If no refresh token is present, the API returns 400 Bad Request.

Logout

Call GET /auth/logout to clear your session cookies. This endpoint requires an active access token.
curl -X GET http://localhost:3100/auth/logout \
  -b cookies.txt \
  -c cookies.txt
The server clears both the access-token and refresh-token cookies and returns { "success": true }.

Account lockout

After a configurable number of failed login attempts, an account is temporarily locked. The lockout duration is set by the server operator via environment variables (AUTH_LOCK_LOGIN_AFTER_FAILED_ATTEMPTS and AUTH_LOCK_LOGIN_COOLDOWN). Subsequent login attempts during the cooldown period will return 401 Unauthorized.

Public endpoints

The following endpoints do not require authentication:
EndpointMethodDescription
/listingsGETBrowse available listings
/applicationsPOSTSubmit a new application
/jurisdictionsGETRead jurisdiction data
/multiselectQuestionsGETRead preferences and programs
/auth/request-mfa-codePOSTRequest an MFA code before login
/auth/update-passwordPUTSet a new password via reset token
/auth/confirmPUTConfirm a new user account

Email confirmation

When a new account is created, the user receives a confirmation email. The account must be confirmed before login is permitted. Resend confirmation with POST /user/resendConfirmation, or confirm directly with PUT /auth/confirm using the token from the email.
curl -X PUT http://localhost:3100/auth/confirm \
  -H 'Content-Type: application/json' \
  -d '{"token": "<confirmation-token-from-email>"}'

Password reset

1

Request a reset link

curl -X PUT http://localhost:3100/user/forgot-password \
  -H 'Content-Type: application/json' \
  -d '{"email": "user@example.com", "appUrl": "https://yourapp.example.com"}'
2

Set a new password

Use the token from the reset email.
curl -X PUT http://localhost:3100/auth/update-password \
  -H 'Content-Type: application/json' \
  -c cookies.txt \
  -d '{"token": "<reset-token>", "password": "newpassword", "passwordConfirmation": "newpassword"}'
On success, the server sets new auth cookies and the user is logged in.

Build docs developers (and LLMs) love