NestboltNestbolt

@nestbolt/authentication

API Routes

Complete reference for all 19 authentication endpoints provided by @nestbolt/authentication, including request bodies, response formats, and error codes.

This page documents every HTTP endpoint registered by the authentication module. Routes are grouped by feature area. All request and response bodies use JSON.

Access tokens are sent as Bearer tokens in the Authorization header:

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

Refresh tokens are sent in the request body.


Core Authentication

These routes are always available, regardless of which features are enabled.

POST /login

Authenticate a user with their credentials. If the user has two-factor authentication enabled, a challenge token is returned instead of access/refresh tokens.

Authentication: None

Rate limiting: LoginThrottleGuard (default: 5 attempts per 60 seconds, per username+IP)

Request body:

{
  "email": "user@example.com",
  "password": "secretpassword",
  "remember": false
}
FieldTypeRequiredDescription
emailstringYesThe user's email (or whatever field usernameField is set to)
passwordstringYesThe user's password
rememberbooleanNoWhether to remember the user (passed to the 2FA challenge token)

Response (no 2FA):

{
  "twoFactor": false,
  "accessToken": "eyJhbGciOiJIUzI1NiIs...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}

Response (2FA required):

{
  "twoFactor": true,
  "challengeToken": "eyJhbGciOiJIUzI1NiIs..."
}

The challengeToken is a short-lived JWT (5 minutes) that must be sent to POST /two-factor-challenge along with a TOTP code or recovery code.

Error responses:

StatusCondition
401 UnauthorizedInvalid credentials
429 Too Many RequestsRate limit exceeded

POST /refresh

Exchange a valid refresh token for a new access/refresh token pair.

Authentication: Refresh token (sent in request body, validated by jwt-refresh strategy)

Request body:

{
  "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}

Response:

{
  "accessToken": "eyJhbGciOiJIUzI1NiIs...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}

Error responses:

StatusCondition
401 UnauthorizedInvalid or expired refresh token

POST /logout

Log the user out. Emits the auth.logout event.

Authentication: JWT Bearer token

Request body: None

Response:

{
  "message": "Logged out successfully."
}

Error responses:

StatusCondition
401 UnauthorizedMissing or invalid access token

Registration

Requires: Feature.REGISTRATION

POST /register

Create a new user account and return access/refresh tokens.

Authentication: None

Request body:

{
  "name": "Jane Doe",
  "email": "jane@example.com",
  "password": "secretpassword",
  "passwordConfirmation": "secretpassword"
}
FieldTypeRequiredValidation
namestringYesNot empty, max 255 characters
emailstringYesValid email, max 255 characters
passwordstringYesMin 8 characters
passwordConfirmationstringYesNot empty

Response (201 Created):

{
  "twoFactor": false,
  "accessToken": "eyJhbGciOiJIUzI1NiIs...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}

Error responses:

StatusCondition
400 Bad RequestValidation errors
404 Not FoundFeature not enabled
409 ConflictUser already exists (if your CreatesNewUsers implementation throws this)
500 Internal Server ErrorMissing CREATES_NEW_USERS provider

Password Reset

Requires: Feature.RESET_PASSWORDS

POST /forgot-password

Request a password reset token. The raw token is returned in the response -- you are responsible for delivering it to the user (e.g., via email).

Authentication: None

Request body:

{
  "email": "user@example.com"
}
FieldTypeRequiredValidation
emailstringYesValid email

Response:

{
  "message": "If the email exists, a reset link has been sent."
}

The response message is intentionally vague to prevent email enumeration. The raw token is also returned in the response object (access it via the token field in the PasswordResetService.sendResetLink() return value).

Error responses:

StatusCondition
400 Bad RequestValidation errors
404 Not FoundFeature not enabled

POST /reset-password

Reset the user's password using a valid reset token.

Authentication: None

Request body:

{
  "email": "user@example.com",
  "token": "a1b2c3d4e5f6...",
  "password": "newsecretpassword",
  "passwordConfirmation": "newsecretpassword"
}
FieldTypeRequiredValidation
emailstringYesValid email
tokenstringYesNot empty
passwordstringYesMin 8 characters
passwordConfirmationstringYesNot empty

Response:

{
  "message": "Your password has been reset."
}

Error responses:

StatusCondition
400 Bad RequestValidation errors
404 Not FoundFeature not enabled
422 Unprocessable EntityInvalid token, expired token (older than 60 minutes), or user not found

Email Verification

Requires: Feature.EMAIL_VERIFICATION

GET /email/verify/:id/:hash

Verify a user's email address using a signed URL.

Authentication: JWT Bearer token

Query parameters:

ParameterTypeRequiredDescription
signaturestringYesHMAC-SHA256 signature of the verification payload
expiresstringYesUnix timestamp when the link expires

Response:

{
  "message": "Email verified successfully."
}

Error responses:

StatusCondition
400 Bad RequestMissing signature or expires parameter, or user not found
401 UnauthorizedUser ID in URL does not match authenticated user
404 Not FoundFeature not enabled
422 Unprocessable EntityLink expired, invalid hash, or invalid signature

POST /email/verification-notification

Request a new verification notification. Returns the verification data needed to construct a verification URL.

Authentication: JWT Bearer token

Rate limiting: VerificationThrottleGuard (default: 6 requests per 60 seconds)

Request body: None

Response (email not yet verified):

{
  "message": "Verification link sent.",
  "id": "user-uuid",
  "hash": "abc123...",
  "signature": "def456...",
  "expires": "1712500000000"
}

Response (email already verified):

{
  "message": "Email already verified."
}

Error responses:

StatusCondition
401 UnauthorizedMissing or invalid access token
404 Not FoundFeature not enabled
429 Too Many RequestsRate limit exceeded

Profile Management

Requires: Feature.UPDATE_PROFILE_INFORMATION

PUT /user/profile-information

Update the authenticated user's profile information.

Authentication: JWT Bearer token

Request body:

{
  "name": "Jane Smith",
  "email": "jane.smith@example.com"
}
FieldTypeRequiredValidation
namestringNoMax 255 characters
emailstringNoValid email, max 255 characters

Both fields are optional -- send only the fields you want to update.

Response:

{
  "message": "Profile information updated."
}

Error responses:

StatusCondition
400 Bad RequestValidation errors
401 UnauthorizedMissing or invalid access token
404 Not FoundFeature not enabled
500 Internal Server ErrorMissing UPDATES_USER_PROFILE provider

Password Update

Requires: Feature.UPDATE_PASSWORDS

PUT /user/password

Change the authenticated user's password. Requires the current password for verification.

Authentication: JWT Bearer token

Request body:

{
  "currentPassword": "oldsecretpassword",
  "password": "newsecretpassword",
  "passwordConfirmation": "newsecretpassword"
}
FieldTypeRequiredValidation
currentPasswordstringYesNot empty
passwordstringYesMin 8 characters
passwordConfirmationstringYesNot empty

Response:

{
  "message": "Password updated."
}

Error responses:

StatusCondition
400 Bad RequestValidation errors
401 UnauthorizedMissing or invalid access token
404 Not FoundFeature not enabled
422 Unprocessable EntityCurrent password incorrect (if your action throws this)
500 Internal Server ErrorMissing UPDATES_USER_PASSWORDS provider

Password Confirmation

These routes are always available (not feature-gated).

POST /user/confirm-password

Confirm the user's password. Stores a timestamp that the PasswordConfirmedGuard checks when guarding sensitive operations.

Authentication: JWT Bearer token

Request body:

{
  "password": "secretpassword"
}
FieldTypeRequiredValidation
passwordstringYesNot empty

Response (password correct):

{
  "confirmed": true
}

Error responses:

StatusCondition
401 UnauthorizedMissing or invalid access token
422 Unprocessable EntityIncorrect password

GET /user/confirmed-password-status

Check whether the user has recently confirmed their password.

Authentication: JWT Bearer token

Query parameters:

ParameterTypeRequiredDescription
secondsstringNoOverride the default timeout (in seconds). Defaults to passwordTimeout option (900).

Response:

{
  "confirmed": true
}

or

{
  "confirmed": false
}

Two-Factor Authentication

Requires: Feature.TWO_FACTOR_AUTHENTICATION

POST /user/two-factor-authentication

Enable two-factor authentication for the authenticated user. Generates a TOTP secret and 8 recovery codes, stored encrypted in the database.

Authentication: JWT Bearer token

Guard: PasswordConfirmedGuard (active when twoFactorOptions.confirmPassword is true)

Request body (optional):

{
  "force": true
}
FieldTypeRequiredDescription
forcebooleanNoIf true, regenerates the secret even if 2FA is already enabled

Response:

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

DELETE /user/two-factor-authentication

Disable two-factor authentication. Removes the TOTP secret, recovery codes, and confirmation timestamp.

Authentication: JWT Bearer token

Guard: PasswordConfirmedGuard

Request body: None

Response:

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

POST /user/confirmed-two-factor-authentication

Confirm the 2FA setup by providing a valid TOTP code from the user's authenticator app. This sets the twoFactorConfirmedAt timestamp.

Required when twoFactorOptions.confirm is true. Without confirmation, the 2FA setup is not enforced during login.

Authentication: JWT Bearer token

Guard: PasswordConfirmedGuard

Request body:

{
  "code": "123456"
}
FieldTypeRequiredValidation
codestringYesNot empty

Response:

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

Error responses:

StatusCondition
422 Unprocessable EntityInvalid TOTP code or 2FA not enabled

GET /user/two-factor-qr-code

Get a QR code for setting up 2FA in an authenticator app. Returns the QR code as an SVG string and the otpauth URL.

Authentication: JWT Bearer token

Guard: PasswordConfirmedGuard

Response:

{
  "svg": "<svg xmlns=\"http://www.w3.org/2000/svg\" ...",
  "url": "otpauth://totp/MyApp:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=MyApp"
}

Error responses:

StatusCondition
404 Not Found2FA not enabled for this user

GET /user/two-factor-secret-key

Get the raw TOTP secret key (base32-encoded). Useful for manual entry in authenticator apps that do not support QR code scanning.

Authentication: JWT Bearer token

Guard: PasswordConfirmedGuard

Response:

{
  "secretKey": "JBSWY3DPEHPK3PXP"
}

Error responses:

StatusCondition
404 Not Found2FA not enabled for this user

GET /user/two-factor-recovery-codes

Get the current list of recovery codes for the authenticated user.

Authentication: JWT Bearer token

Guard: PasswordConfirmedGuard

Response:

[
  "aBcDeFgHiJ-kLmNoPqRsT",
  "uVwXyZ0123-4567890abc",
  "..."
]

Returns an empty array if 2FA is not enabled.


POST /user/two-factor-recovery-codes

Regenerate all recovery codes. Replaces the existing codes with 8 new ones.

Authentication: JWT Bearer token

Guard: PasswordConfirmedGuard

Response:

{
  "message": "Recovery codes regenerated."
}

POST /two-factor-challenge

Complete a two-factor authentication challenge during login. This is the second step of the login flow when the user has 2FA enabled.

Authentication: None (uses the challenge token from the login response)

Rate limiting: TwoFactorThrottleGuard (default: 5 attempts per 60 seconds, per IP)

Request body (with TOTP code):

{
  "challengeToken": "eyJhbGciOiJIUzI1NiIs...",
  "code": "123456"
}

Request body (with recovery code):

{
  "challengeToken": "eyJhbGciOiJIUzI1NiIs...",
  "recoveryCode": "aBcDeFgHiJ-kLmNoPqRsT"
}
FieldTypeRequiredDescription
challengeTokenstringYesThe challenge token from the login response
codestringNoA 6-digit TOTP code from the authenticator app
recoveryCodestringNoA recovery code

One of code or recoveryCode must be provided.

Response:

{
  "twoFactor": false,
  "accessToken": "eyJhbGciOiJIUzI1NiIs...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}

Error responses:

StatusCondition
400 Bad RequestNeither code nor recoveryCode provided
401 UnauthorizedInvalid or expired challenge token
422 Unprocessable EntityInvalid TOTP code or recovery code
429 Too Many RequestsRate limit exceeded

Error Response Format

All error responses follow the standard NestJS exception format:

{
  "statusCode": 422,
  "message": "The provided two-factor code was invalid.",
  "error": "Unprocessable Entity"
}

For validation errors (400 Bad Request), the message field is an array of validation error strings:

{
  "statusCode": 400,
  "message": [
    "email must be an email",
    "password must be longer than or equal to 8 characters"
  ],
  "error": "Bad Request"
}

Next Steps

  • Decorators and Guards -- use the package's decorators and guards in your own controllers.
  • Events -- subscribe to authentication lifecycle events.