curl --request POST \
--url https://pria.praxislxp.com/api/auth/mfa-verify \
--header 'Content-Type: application/json' \
--data '
{
"challengeId": "65f2c9a1d8e4b3c5a1234567",
"code": "472918"
}
'import requests
url = "https://pria.praxislxp.com/api/auth/mfa-verify"
payload = {
"challengeId": "65f2c9a1d8e4b3c5a1234567",
"code": "472918"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({challengeId: '65f2c9a1d8e4b3c5a1234567', code: '472918'})
};
fetch('https://pria.praxislxp.com/api/auth/mfa-verify', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://pria.praxislxp.com/api/auth/mfa-verify",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'challengeId' => '65f2c9a1d8e4b3c5a1234567',
'code' => '472918'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://pria.praxislxp.com/api/auth/mfa-verify"
payload := strings.NewReader("{\n \"challengeId\": \"65f2c9a1d8e4b3c5a1234567\",\n \"code\": \"472918\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://pria.praxislxp.com/api/auth/mfa-verify")
.header("Content-Type", "application/json")
.body("{\n \"challengeId\": \"65f2c9a1d8e4b3c5a1234567\",\n \"code\": \"472918\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://pria.praxislxp.com/api/auth/mfa-verify")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"challengeId\": \"65f2c9a1d8e4b3c5a1234567\",\n \"code\": \"472918\"\n}"
response = http.request(request)
puts response.read_body{
"token": "<string>",
"profile": {
"_id": "<string>",
"email": "jsmith@example.com",
"fname": "<string>",
"lname": "<string>",
"picture": "<string>",
"accountType": "<string>",
"permissions": [
"<string>"
],
"customerId": "<string>",
"lxp_user_id": "<string>",
"lxp_user_type": 123,
"lxp_partner_id": "<string>",
"lxp_partner_name": "<string>",
"lxp_role_id": 123,
"lxp_role_name": "<string>",
"credits": 123,
"creditsUsed": 123,
"plan": "<string>",
"status": "<string>",
"trial_end": "2023-11-07T05:31:56Z",
"trial_used": true,
"current_period_end": "2023-11-07T05:31:56Z",
"cancel_at_period_end": true,
"referralId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"referrerPaid": true,
"resetCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"invoices_urls": [
"<string>"
],
"remember_history_count": 123,
"browser_voice": "<string>",
"rt_voice": "<string>",
"use_location": true,
"showSideBar": true,
"dark_mode": true,
"created": "2023-11-07T05:31:56Z",
"__v": 123,
"institution": {
"_id": "<string>",
"name": "<string>",
"picture": "<string>",
"picture_bg": "<string>",
"picture_dark_bg": "<string>",
"picture_animated": "<string>",
"elevenlabs_agent_id": "<string>",
"credits": 123,
"status": "<string>",
"allowJoining": "<string>",
"joiningAdminOnly": true,
"publicId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"publicAuthorizedUrls": [
"<string>"
],
"ainame": "<string>",
"contactEmail": "jsmith@example.com",
"creditAward": 123,
"poolCredits": true,
"invoices_urls": [
"<string>"
],
"maxCompletionTokens": 123,
"disableFileUploadForUser": true,
"disableAudioNotesForUser": true,
"toolsDisabled": [
"<string>"
],
"ltiContextIds": [
"<string>"
],
"personalisationAsked": true,
"locationEnabled": true,
"rtEnabled": true,
"rtAdminOnly": true,
"displayAgentDetails": true,
"displayThinkingDetails": true,
"displayRagSearchDetails": true,
"displayMemoryDetails": true,
"displayThinkingExecution": true,
"displayToolExecution": true,
"assistantsDisabled": [
"<string>"
],
"disableAssistantsForUser": true,
"rtVoice": "<string>",
"maxFiles": 123,
"questionType": "<string>",
"creditsTotal": 123,
"creditsUsagePct": 123,
"id": "<string>",
"account": {
"_id": "<string>",
"name": "<string>",
"status": "<string>",
"canvasCredsResolved": true,
"privacyPolicyHTML": "<string>",
"privacyPolicyUpdatedAt": "2023-11-07T05:31:56Z",
"privacyPolicyHash": "3bfb489f9bd077f0"
}
}
}
}{
"success": false,
"code": "BAD_REQUEST",
"message": "<string>",
"attemptsRemaining": 4,
"retryAfter": 24,
"serverTime": 1790000000
}{
"success": false,
"code": "BAD_REQUEST",
"message": "<string>",
"attemptsRemaining": 4,
"retryAfter": 24,
"serverTime": 1790000000
}{
"success": false,
"code": "BAD_REQUEST",
"message": "<string>",
"attemptsRemaining": 4,
"retryAfter": 24,
"serverTime": 1790000000
}{
"success": false,
"code": "BAD_REQUEST",
"message": "<string>",
"attemptsRemaining": 4,
"retryAfter": 24,
"serverTime": 1790000000
}{
"success": false,
"code": "BAD_REQUEST",
"message": "<string>",
"attemptsRemaining": 4,
"retryAfter": 24,
"serverTime": 1790000000
}Submit a 6-digit MFA code to complete login
Second leg of the MFA login flow. The first leg (POST /api/auth/signin
or /autosignup) returned {mfaRequired: true, challengeId, maskedEmail}
and emailed a 6-digit code. This endpoint accepts the typed code, and
on success returns the same shape as a normal signin response (token +
profile) and sets a long-lived pria_mfa_trust cookie that lets the
same browser skip MFA for the next 7 days (or whatever MFA_TRUST_DAYS
sets, bounded to [1, 30]).
Embedded (SDK / Canvas) launches: when the code was requested from
an SDK launch, the success answer also carries mfaTrust, a device
handle for the embedded page. The page keeps it and sends it as
mfaTrust in the body of its later SDK launches (the embedded frame
never receives the cookie). It lasts 24 hours, or until trusted
devices are signed out in Security settings or the password changes;
logging out inside the embedded page also forgets it. It is honoured
only on SDK launches (/api/auth/autosignup with institution_id or
lticontextid), for the same person, from the same network.
The accepted code signs the person in to the Digital Twin and course the launch named, with
the launch’s own checks: a Digital Twin that is no longer usable answers 400 with the reason;
a Digital Twin that requires Canvas sign-in answers { consent, mfaTrust }, and the launch
that follows the Canvas step needs no second code when it carries that mfaTrust. A launch
challenge answers only on the network that started it (see 410).
Brute-force protection: 5 wrong attempts per code; the 6th burns
the challenge (status invalidated) and the user must request a new
code via /mfa-resend. Every wrong code also counts toward the person’s
limit for that kind of sign-in (an embedded / Canvas launch, a password
sign-in, or any other sign-in): 10 an hour or 20 a day. Over it, that
kind of sign-in answers 423 MFA_LOCKED with retryAfter (seconds) —
here and at sign-in — while the other kinds stay open; the wrong code
that reaches the limit already answers 423. A correct code clears the
count; an administrator can clear it by changing the person’s MFA setting
or signing out their trusted devices.
Rate limit: 100 req/min per IP (authLimiter).
curl --request POST \
--url https://pria.praxislxp.com/api/auth/mfa-verify \
--header 'Content-Type: application/json' \
--data '
{
"challengeId": "65f2c9a1d8e4b3c5a1234567",
"code": "472918"
}
'import requests
url = "https://pria.praxislxp.com/api/auth/mfa-verify"
payload = {
"challengeId": "65f2c9a1d8e4b3c5a1234567",
"code": "472918"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({challengeId: '65f2c9a1d8e4b3c5a1234567', code: '472918'})
};
fetch('https://pria.praxislxp.com/api/auth/mfa-verify', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://pria.praxislxp.com/api/auth/mfa-verify",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'challengeId' => '65f2c9a1d8e4b3c5a1234567',
'code' => '472918'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://pria.praxislxp.com/api/auth/mfa-verify"
payload := strings.NewReader("{\n \"challengeId\": \"65f2c9a1d8e4b3c5a1234567\",\n \"code\": \"472918\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://pria.praxislxp.com/api/auth/mfa-verify")
.header("Content-Type", "application/json")
.body("{\n \"challengeId\": \"65f2c9a1d8e4b3c5a1234567\",\n \"code\": \"472918\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://pria.praxislxp.com/api/auth/mfa-verify")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"challengeId\": \"65f2c9a1d8e4b3c5a1234567\",\n \"code\": \"472918\"\n}"
response = http.request(request)
puts response.read_body{
"token": "<string>",
"profile": {
"_id": "<string>",
"email": "jsmith@example.com",
"fname": "<string>",
"lname": "<string>",
"picture": "<string>",
"accountType": "<string>",
"permissions": [
"<string>"
],
"customerId": "<string>",
"lxp_user_id": "<string>",
"lxp_user_type": 123,
"lxp_partner_id": "<string>",
"lxp_partner_name": "<string>",
"lxp_role_id": 123,
"lxp_role_name": "<string>",
"credits": 123,
"creditsUsed": 123,
"plan": "<string>",
"status": "<string>",
"trial_end": "2023-11-07T05:31:56Z",
"trial_used": true,
"current_period_end": "2023-11-07T05:31:56Z",
"cancel_at_period_end": true,
"referralId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"referrerPaid": true,
"resetCodeId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"invoices_urls": [
"<string>"
],
"remember_history_count": 123,
"browser_voice": "<string>",
"rt_voice": "<string>",
"use_location": true,
"showSideBar": true,
"dark_mode": true,
"created": "2023-11-07T05:31:56Z",
"__v": 123,
"institution": {
"_id": "<string>",
"name": "<string>",
"picture": "<string>",
"picture_bg": "<string>",
"picture_dark_bg": "<string>",
"picture_animated": "<string>",
"elevenlabs_agent_id": "<string>",
"credits": 123,
"status": "<string>",
"allowJoining": "<string>",
"joiningAdminOnly": true,
"publicId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"publicAuthorizedUrls": [
"<string>"
],
"ainame": "<string>",
"contactEmail": "jsmith@example.com",
"creditAward": 123,
"poolCredits": true,
"invoices_urls": [
"<string>"
],
"maxCompletionTokens": 123,
"disableFileUploadForUser": true,
"disableAudioNotesForUser": true,
"toolsDisabled": [
"<string>"
],
"ltiContextIds": [
"<string>"
],
"personalisationAsked": true,
"locationEnabled": true,
"rtEnabled": true,
"rtAdminOnly": true,
"displayAgentDetails": true,
"displayThinkingDetails": true,
"displayRagSearchDetails": true,
"displayMemoryDetails": true,
"displayThinkingExecution": true,
"displayToolExecution": true,
"assistantsDisabled": [
"<string>"
],
"disableAssistantsForUser": true,
"rtVoice": "<string>",
"maxFiles": 123,
"questionType": "<string>",
"creditsTotal": 123,
"creditsUsagePct": 123,
"id": "<string>",
"account": {
"_id": "<string>",
"name": "<string>",
"status": "<string>",
"canvasCredsResolved": true,
"privacyPolicyHTML": "<string>",
"privacyPolicyUpdatedAt": "2023-11-07T05:31:56Z",
"privacyPolicyHash": "3bfb489f9bd077f0"
}
}
}
}{
"success": false,
"code": "BAD_REQUEST",
"message": "<string>",
"attemptsRemaining": 4,
"retryAfter": 24,
"serverTime": 1790000000
}{
"success": false,
"code": "BAD_REQUEST",
"message": "<string>",
"attemptsRemaining": 4,
"retryAfter": 24,
"serverTime": 1790000000
}{
"success": false,
"code": "BAD_REQUEST",
"message": "<string>",
"attemptsRemaining": 4,
"retryAfter": 24,
"serverTime": 1790000000
}{
"success": false,
"code": "BAD_REQUEST",
"message": "<string>",
"attemptsRemaining": 4,
"retryAfter": 24,
"serverTime": 1790000000
}{
"success": false,
"code": "BAD_REQUEST",
"message": "<string>",
"attemptsRemaining": 4,
"retryAfter": 24,
"serverTime": 1790000000
}Body
Opaque server-issued challenge identifier returned by POST /api/auth/signin (or /autosignup) when the response carried mfaRequired=true.
"65f2c9a1d8e4b3c5a1234567"
The 6-digit numeric code the user received by email.
^[0-9]{6}$"472918"
Was this page helpful?