RAID API
  1. Auth
  • DiveRAID frontend public API
    • Search divers
      POST
    • Search instructors
      POST
    • Search dive centers
      POST
    • Search dive centers by country
      GET
  • DiveRAID rest API V1
    • Auth
      • Register a new user
        POST
      • Login and get a Sanctum token
        POST
      • Send password reset email
        POST
      • Reset password using token
        POST
      • Logout and revoke the current token
        POST
      • Resend email verification
        POST
      • Complete a two-factor login and get a Sanctum token
        POST
    • Profile
      • The user resource
      • Get authenticated user profile
      • Update profile
      • Delete account
      • Update password
      • Update dive center association
    • Diver
      • Shared diver resources
      • Courses
        • List active courses
        • List expired courses
        • Get course detail
        • Submit module quiz
        • Get quiz result
        • Submit course exam
        • Get exam result
        • Get skills progress
        • Sign skills (diver)
      • Free Learnings
        • List enrolled free learnings
        • List available free learning courses
        • Enroll in a free learning course
        • Get free learning detail
        • Submit free learning module quiz
        • Get free learning quiz result
      • Certifications
        • Get certification history
        • Get certification quiz result
        • Get certification exam result
        • Get certification skills
        • List diver certifications
      • Dive Logs
        • Delete dive log
        • Create dive log
        • Update dive log
        • List loggable courses
        • List dive logs (paginated)
        • Get dive log
      • Awards
        • List award cards
      • Documents
        • Upload own medical certificate or insurance
        • List diver documents
      • Forms
        • List diver forms
      • Medical
        • Get medical questionnaire structure
        • Submit medical questionnaire
      • Store
        • List courses available for purchase
        • Get order status
    • Professional
      • Students
        • List students
        • Get student progress
        • Get student quiz result
        • Get student exam result
        • Get student skills progress
        • Sign student skills
      • Certifications
        • Get certification history
        • Get certification quiz result
        • Get certification exam result
        • Get certification skills
        • List all professional certifications
        • List diver-level certifications
        • List specialty certifications
        • List professional certifications
        • List trainer certifications
        • List examiner certifications
      • Classroom
        • List classrooms
        • Get classroom progress (all students)
        • Get classroom student progress
        • Get classroom student quiz result
        • Get classroom student exam result
        • Get classroom student skills
        • Sign classroom student skills
      • Renewals
        • List renewal courses
        • Get renewal progress
        • Renewal status
        • Submit renewal module quiz
        • Get renewal quiz result
        • Submit renewal exam
        • Get renewal exam result
        • Get renewal skills progress
        • Sign renewal skills
      • Recognitions
        • List recognition courses
      • Dive Logs
        • Get student dive log
        • Sign student dive log
        • List student dive logs for a course
      • Store
    • Sync
      • Upload offline operations
      • Download full course data for offline use
      • Get sync status
    • Dive Center
    • Public
      • List all countries
      • Dive-log enum values with labels in the response language
      • Get country data
      • Get country divisions (states/provinces)
      • List time zone identifiers, optionally narrowed to one country
      • List, search, and radius-search publicly visible dive centres
      • Every publicly visible, geolocated dive centre as a map marker
      • Countries with at least one publicly visible dive centre
      • Full detail of one publicly visible dive centre
  • Schemas
    • Frontend API Schema
      • DiverSearch
    • SuccessResponse
    • DiverCertification
    • ValidationErrorResponse
    • TwoFactorChallengeResponse
    • TokenResponse
    • ErrorResponse
    • DiveLog
    • UserProfile
    • CourseLog
    • CourseLogDetail
    • QuizResult
    • ExamResult
    • SkillProgress
    • Certification
    • PaginatedDiveLogs
    • StoreItem
    • PaymentIntentResponse
    • OrderConfirmResponse
    • OrderStatusResponse
    • InstructorSearch
    • DiveCenterSearch
  1. Auth

Complete a two-factor login and get a Sanctum token

POST
https://test.diveraid.com/api/v1/auth/two-factor-challenge
V1 Auth
Maintainer:Not configured

Overview#

Second step of a login for an account that has two-factor authentication enabled. POST /api/v1/auth/login answers such an account with a challenge_token instead of a token. This endpoint exchanges that challenge, plus either a current authenticator (TOTP) code or one recovery code, for the same Sanctum personal access token a plain login returns.
A challenge lives 5 minutes, can be redeemed once, and is invalidated after 5 wrong codes. In every one of those cases the client starts again from POST /api/v1/auth/login.
Enabling, confirming and disabling two-factor authentication are not available over the API: they stay on the website.
Controller: App\Http\Controllers\Api\V1\Auth\AuthController::twoFactorChallenge()
Route name: api.v1.auth.two-factor-challenge

Authentication#

Type: None. Public endpoint. The challenge_token in the body is the only credential, and it is not a bearer token: sent as Authorization: Bearer it answers 401 Invalid token.
Additional middleware: throttle:two-factor-api — 5 requests per minute per challenge and 10 requests per minute per IP address. This budget is separate from the throttle:auth budget shared by register, login, password/forgot and password/reset.

Request#

Method: POST
Path: /api/v1/auth/two-factor-challenge
Content-Type: application/json

Body#

{
  "challenge_token": "Zx9kQ2mV7bT4nW1cR8yH5pL0dJ3sF6uAeG2tB9vKq4XoM7iNzC5wY1rD8hE3jP6a",
  "code": "123456"
}
FieldTypeRequiredValidationDescription
challenge_tokenstringYesrequired|string|max:255The data.challenge_token returned by POST /api/v1/auth/login
codestringOne of code / recovery_codenullable|string|max:16|required_without:recovery_code|prohibits:recovery_codeCurrent TOTP code from the authenticator app
recovery_codestringOne of code / recovery_codenullable|string|max:64|required_without:codeOne unused recovery code
Send exactly one of code and recovery_code. Validated by App\Http\Requests\Api\V1\Auth\TwoFactorChallengeRequest.

Example request#


Response 200 OK#

{
  "success": true,
  "status": "success",
  "message": "OK",
  "data": {
    "token": "1|raid_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "token_type": "Bearer",
    "expires_in": 7775999
  }
}
The payload is identical to a successful POST /api/v1/auth/login for an account without two-factor authentication, and is documented there. The token is named with the device_name sent to the login request that issued the challenge (or the label derived from the User-Agent), not with anything sent here.

Errors#

422 Unprocessable Entity — wrong code#

Returned for a wrong TOTP code, a TOTP code that was already accepted inside its validity window, or a recovery code that is unknown or already used. The key is code or recovery_code, matching the field sent. A wrong code counts towards the 5 failures that invalidate the challenge.
{
  "success": false,
  "status": "error",
  "message": "Validation failed",
  "errors": {
    "code": ["The provided two factor authentication code was invalid."]
  }
}
For recovery_code the message is The provided two factor recovery code was invalid.

422 Unprocessable Entity — unknown, expired or used challenge#

The same response for a challenge that never existed, has expired, was already redeemed, or was invalidated by 5 failures. It does not say which, and it never says whether the account exists.
{
  "success": false,
  "status": "error",
  "message": "Validation failed",
  "errors": {
    "challenge_token": ["The two-factor challenge is invalid or has expired."]
  }
}

422 Unprocessable Entity — validation#

Missing challenge_token, neither or both of code and recovery_code. For example, with both sent:
{
  "success": false,
  "status": "error",
  "message": "Validation failed",
  "errors": {
    "code": ["The code field prohibits recovery code from being present."]
  }
}

429 Too Many Requests#

{
  "success": false,
  "status": "error",
  "message": "Too many requests"
}
Retry-After header present. The throttle:two-factor-api limiter allows 5 requests per minute per challenge_token and 10 per minute per IP address, counting successful and failed attempts alike.

Notes#

A recovery code works once. Redeeming it replaces it with a newly generated one on the account; the number of recovery codes does not change.
A TOTP code cannot be used twice inside its validity window, even on a different challenge.
The challenge is held server-side and only a hash of the token is stored. It is deleted as soon as it is redeemed.
Nothing about the account is revealed before the second factor is accepted: a wrong password and an unknown email both answer 401 Invalid credentials at login, and a challenge answers the same 422 whatever happened to it.

Source: docs/api/auth/POST_two_factor_challenge.md

Request

Body Params application/jsonRequired

Examples

Responses

🟢200
application/json
Second factor accepted. Same payload as a login without two-factor authentication.
Bodyapplication/json

🟠422
🟠429
Request Request Example
Shell
JavaScript
Java
Swift
curl --location 'https://test.diveraid.com/api/v1/auth/two-factor-challenge' \
--header 'Content-Type: application/json' \
--data '{}'
Response Response Example
200 - Example 1
{
    "status": "success",
    "message": "string",
    "data": {
        "token": "string",
        "token_type": "Bearer",
        "expires_in": 0
    }
}
Modified at 2026-10-07 16:00:31
Previous
Resend email verification
Next
The user resource
Built with