Auth

RelayBox Auth handles user authentication, session management, and multi-factor authentication (MFA). It provides methods for signing up, logging in, refreshing tokens, managing user sessions, and OAuth provider login. Auth provides a higher level of securty and interaction capability for your application.

Getting started

To initialize auth, simply pass a public key to the RelayBox constructor. A public key consists of the first 2 parts of any API key.

For example, if your API key is...

12345.abcde.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Your public key will be...

12345.abcde

The third part of the API key is the secret key used to sign authentication tokens and should never be exposed to end users. To generate an API key, head over to the dashboard and locate the "API keys" section under any of your applications.

const relayBox = new RelayBox({
  publicKey: xxxx.xxxx // Replace with your public key
});

Once initialized you can now access auth functionality within your application via the auth namespace. For example...

const authUserSession = await relayBox.auth.getSession();

Auth provides the means to create and manage every aspect of the realtime user journey through your applications. Users created using the auth service have full access to realtime services once system authentication is complete.


The AuthUserSession Object

After successful authentication, the authentication service returns an object containing data about the logged-in user, along with the credentials required to access realtime services.

The authentication tokens within the session object can also be used as a standalone authentication mechanism for your own backend services through the use of cryptographically signed JWT tokens. See the @relaybox/rest documentation for more information.

An AuthUserSession object returned by the authentication service looks like this...

{
  "session": {
    "token": "xxxxx.xxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "refreshToken": "xxxxx.xxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "expiresIn": 300,
    "expiresAt": 1726174042498,
    "destroyAt": 1726177342498,
    "authStorageType": "persist"
  },
  "user": {
    "id": "af8f910e-c72c-4335-a104-48212ad65c1f",
    "orgId": "8f6a2232-63e2-4ff7-969f-417739d155ed",
    "appId": "675e81c4-2b88-4167-a33b-0d564d2548a5",
    "username": "fringedfudge300",
    "clientId": "0fyWl1VWj8Nx",
    "email": "hello@universe.com",
    "createdAt": "2024-09-10T18:14:48.758Z",
    "updatedAt": "2024-09-12T11:22:30.194Z",
    "verifiedAt": "2024-09-10T18:19:45.952Z",
    "authMfaEnabled": true,
    "blockedAt": null,
    "identities": [
      {
        "id": "654e6295-6927-4ce2-98b1-dca79a868f05",
        "provider": "github",
        "providerId": "123456",
        "verifiedAt": "2024-09-10T18:14:48.908"
      },
      {
        "id": "fc7c67c7-315d-4bfd-8ae3-8e58bc36d4ae",
        "provider": "google",
        "providerId": "123456",
        "verifiedAt": "2024-09-10T20:25:42.719"
      },
      {
        "id": "55734265-ba2a-4cf8-b41b-3cd63d097a04",
        "provider": "email",
        "providerId": null,
        "verifiedAt": "2024-09-10T18:19:45.952"
      }
    ],
    "factors": [
      {
        "id": "0aa7af26-3313-40ae-9857-24ae66ea939e",
        "type": "totp",
        "verifiedAt": "2024-09-10T18:21:07.231"
      }
    ]
  }
}

Error handling

Auth operations are asynchronous and may result in errors being thrown. All errors follow a standard format and can be handled using try/catch or Promise.catch() syntax.

Handled errors will follow a standard format and contain the following data...

{
  name: string, // error name
  status: number, // HTTP status code
  message: string, // human readable error message
  data: any // data relevant to the failure
}

A real-world example might look something like the following...

try {
  const session = await relayBox.auth.signIn({
    email: 'unregistered@relaybox.net',
    password: 'my-super-secure-but-incorrect-password'
  });
} catch (err) {
  console.log(err.name); // UnauthorizedError
  console.log(err.status); // 401
  console.log(err.message); // Login failed
  console.log(err.data); // { message: 'Login failed' }
}

By using named errors and status codes, we hope this will assist with handling errors and presenting a clean UI to your userbase when something inevitably goes wrong.


auth.onAuthEvent()

Authentication events are emmited from all auth service actions.

relayBox.auth.onAuthEvent('SIGN_IN', (session: any) => {
  console.log(session)
});
EventDescription
SIGN_UPEmitted following successful user registration.
VERIFYEmitted following successful account verification.
SIGN_INEmitted following successful sign in (including MFA verify).
SIGN_OUTEmitted following user sign out.
GET_SESSIONEmitted after sucessful user session request.
RESEND_VERIFICATIONEmitted after regitration verification code has been resent.
MFA_ENROLLEmitted following successful MFA enrollment.
MFA_CHALLENGEEmitted after a sucessful MFA challenge.
MFA_REQUIREDEmitted when MFA verification is requred following authentication.
TOKEN_REFRESHEmitted following successful token refresh request.
SESSION_EXPIRED

Emitted following session expiry. The event will be emitted when an auth token is being refreshed automatically due to expiry or during a manual tokenRefresh operation.

PASSWORD_RESETEmitted following initiation of password reset request.
PASSWORD_CONFIRMEmitted following succesful password reset confirmation.

auth.signUp()

Asynchronous function to register a new user account.

const response = await relayBox.auth.signUp({
  email: 'hello@universe.com',
  password: 'my-super-secure-password',
  username: 'fringedfudge300',
  firstName: 'Fringe',
  lastName: 'Fudge'
});
OptionsDescriptionType
email

Valid email address: The email address to be associated with the account. A verification code will be sent to this email address to confirm ownership of the account.

string
passwordAccount password: The password to be associated with the account.string
username (optional)

Account username: The username to be associated with the account. If not provided, a unique username will be automatically generated.

string
firstName (optional)User first name: The first name of the user to be associated with the account.string
lastName (optional)Users last name: The last name of the user to be associated with the account.string

Responses

200 OK  Object containing the new user id and client id.

{
  "message": "Registration successful",
  "id": "12345678-1234-1234-1234-123456789012",
  "clientId": "_Tv-388ztXmr"
}

400 Bad Request   SchemaValidationError

Request schema validation errors follow a distinct structure across all auth endpoints providing feedback on the fields that failed validation.

{
  "name": "SchemaValidationError",
  "message": "Schema validation failed",
  "data": [
    {
      "code": "too_small",
      "minimum": 5,
      "type": "string",
      "inclusive": true,
      "exact": false,
      "message": "String must contain at least 5 character(s)",
      "path": [
        "password"
      ]
    }
  ]
}

401 Unauthorized   AuthenticationError

To mitigate the opportunity for enumeration attacks, a standard 401 Unauthorized error will be returned if the email address or username conflicts with an existing account.

{
  "name": "AuthenticationError",
  "message": "Registration failed",
}

400 Bad Request  PasswordRegexError

Password regex errors are returned when a supplied password fails to meet criteria set via the application dashboard.

{
  "name": "PasswordRegexError",
  "message": "Password does not match required pattern"
}

Example:

The following example demonstrates a user sign up request containing both optional and required fields.

const response = await relayBox.auth.signUp({
  email: 'hello@universe.com',
  password: 'my-super-secure-password',
  username: 'fringedfudge300',
  firstName: 'Fringe',
  lastName: 'Fudge'
});

auth.signIn()

Asynchronous function to authenticate a user using email and passsword.

const session = await relayBox.auth.signIn({
  email: 'hello@universe.com',
  password: 'my-super-secure-password'
});
OptionsDescriptionType
emailValid email address: The verified email address associated the user account.string
passwordUser password: The password associated with the account.string

Responses

200 OK  AuthUserSession

{
    "session": {
        "token": "xxxxx.xxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "refreshToken": "xxxxx.xxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "expiresIn": 300,
        "expiresAt": 1726174042498,
        "destroyAt": 1726177342498,
        "authStorageType": "persist"
    },
    "user": {
        "id": "12345678-1234-1234-1234-123456789012",
        "orgId": "12345678-1234-1234-1234-123456789012",
        "appId": "12345678-1234-1234-1234-123456789012",
        "username": "fringedfudge300",
        "clientId": "0fyWl1VWj8Nx",
        "email": "hello@universe.com",
        "createdAt": "2024-09-10T18:14:48.758Z",
        "updatedAt": "2024-09-12T11:22:30.194Z",
        "verifiedAt": "2024-09-10T18:19:45.952Z",
        "authMfaEnabled": true,
        "blockedAt": null,
        "identities": [
            {
                "id": "12345678-1234-1234-1234-123456789012",
                "provider": "github",
                "providerId": "123456",
                "verifiedAt": "2024-09-10T18:14:48.908"
            },
            {
                "id": "12345678-1234-1234-1234-123456789012",
                "provider": "google",
                "providerId": "123456",
                "verifiedAt": "2024-09-10T20:25:42.719"
            },
            {
                "id": "12345678-1234-1234-1234-123456789012",
                "provider": "email",
                "providerId": null,
                "verifiedAt": "2024-09-10T18:19:45.952"
            }
        ],
        "factors": [
            {
                "id": "12345678-1234-1234-1234-123456789012",
                "type": "totp",
                "verifiedAt": "2024-09-10T18:21:07.231"
            }
        ]
    }
}

200 OK  Restricted AuthUserSession

When a user has enrolled in multi factor authentication, the user sign in response object will contain the factors associated with the account along with some basic user information.

{
  "user": {
    "username": "fringedfudge300",
    "authMfaEnabled": true,
    "factors": [
      {
        "id": "12345678-1234-1234-1234-123456789012",
        "type": "totp",
        "verifiedAt": "2024-09-10T18:21:07.231"
      }
    ]
  },
  "session": null,
  "tmpToken": "xxxxxxx.xxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}

401 Unauthorized  UnauthorizedError

To mitigate the opportunity for enumeration attacks, a standard 401 Unauthorized error will be returned if the sign in request fails due to account information validation.

{
  "name": "UnauthorizedError",
  "message": "Login failed"
}

Example:

const session = await relayBox.auth.signIn({
  email: 'hello@universe.com',
  password: 'my-super-secure-password'
});

auth.verify()

Asynchronous function to verify ownership of an email address using the code sent during account registration.

const response = await relayBox.auth.verify({
  email: 'hello@universe.com',
  code: 'xxxxxx'
});
OptionsDescriptionType
emailValid email address: The email address used to create the user account.string
code

Six digit verification code: The verification code sent to the user's email address following registration.

string

Responses

200 OK 

{
  "message": "User verification successful",
}

400 Bad Request   SchemaValidationError

Request schema validation errors follow a distinct structure across all auth endpoints providing feedback on the fields that failed validation.

{
  "name": "SchemaValidationError",
  "message": "Schema validation failed",
  "data": [
    {
      "code": "too_small",
      "minimum": 6,
      "type": "string",
      "inclusive": true,
      "exact": true,
      "message": "String must contain exactly 6 character(s)",
      "path": [
        "code"
      ]
    }
  ]
}

401 Unauthorized  UnauthorizedError

To mitigate the opportunity for enumeration attacks, a standard 401 Unauthorized error will be returned if code verification fails. More specific information about the error can be found in the dashboard user activity logs.

{
  "name": "AuthenticationError",
  "message": "User verification failed",
}

Example:

const session = await relayBox.auth.verify({
  email: 'hello@universe.com',
  code: 'xxxxxx'
});

auth.passwordReset()

Asynchronous function to initiate a password reset request. A verification code will be sent to the email address provided if previously registered with the application.

const result = await relayBox.auth.passwordReset({
  email: 'hello@universe.com',
});
OptionsDescriptionType
emailValid email address: The email address to send the password reset request to.string

Responses

200 OK 

To mitigate the opportunity for enumeration attacks, the response will always return a success message.

{
  message: 'Password reset request initialized'
}

Example:

const result = await relayBox.auth.passwordReset({
  email: 'hello@universe.com',
});

auth.passwordConfirm()

Asynchronous function to confirm a verification code sent via email following a password reset request.

const response = await relayBox.auth.passwordConfirm({
  email: 'hello@universe.com',
  password: 'my-new-super-secure-password',
  code: 'xxxxxx'
});
OptionsDescriptionType
email

Valid email address: The email address used to initiate the password reset request.

string
passwordNew password: The password the user wishes to associate with their account.string
code

Six digit verification code: The verification code sent to the user's email address.

string

Responses

200 OK 

{
  "message": "Password reset successful"
}

400 Bad Request   SchemaValidationError

Request schema validation errors follow a distinct structure across all auth endpoints providing feedback on the fields that failed validation.

{
  "name": "SchemaValidationError",
  "message": "Schema validation failed",
  "data": [
    {
      "code": "too_small",
      "minimum": 6,
      "type": "string",
      "inclusive": true,
      "exact": true,
      "message": "String must contain exactly 6 character(s)",
      "path": [
        "code"
      ]
    }
  ]
}

400 Bad Request  PasswordRegexError

Password regex errors are returned when a supplied password fails to meet criteria set via the application dashboard.

{
  "name": "PasswordRegexError",
  "message": "Password does not match required pattern"
}

401 Unauthorized  UnauthorizedError

To mitigate the opportunity for enumeration attacks, a standard 401 Unauthorized error will be returned if the email address is not recognized or the verification code has expired or is invalid.

{
  "name": "AuthenticationError",
  "message": "Password reset failed",
}

Example:

const response = await relayBox.auth.passwordConfirm({
  email: 'hello@universe.com',
  password: 'my-new-super-secure-password',
  code: '123456'
});

auth.resendVerification()

Asynchronous function to resend a new user signup verification code.

const response = await relayBox.auth.resendVerification({
  email: 'hello@universe.com',
});
OptionsDescriptionType
email

Valid email address: The email address associated with the account to be verified.

string

Responses

200 OK 

To mitigate enumeration attacks, the response will be a success message unless schema validation fails.

{
  "message": "Verification code sent"
}

400 Bad Request   SchemaValidationError

Request schema validation errors follow a distinct structure across all auth endpoints providing feedback on the fields that failed validation.

{
  "name": "SchemaValidationError",
  "message": "Schema validation failed",
  "data": [
    {
      "validation": "email",
      "code": "invalid_string",
      "message": "Invalid email",
      "path": [
        "email"
      ]
    }
  ]
}

Example:

const session = await relayBox.auth.resendVerification({
  email: 'hello@universe.com'
});

auth.signOut()

Synchronous function to sign a user out of the application. Destroys the current session including authentication and refresh tokens.

relayBox.auth.signOut();

Example:

relayBox.auth.signOut();

auth.tokenRefresh()

Asynchronous function to refresh the logged in user's authentication token. This is a helper method that should be used with caution. The recommended approach is to set the token expiry and let the application automatically handle refreshing the token at regular intervals.

const result = await relayBox.auth.tokenRefresh();

Responses

200 OK 

A sucessful response will contain a new authentication token, along with relevant expiry information.

{
  "token": "xxxxxx.xxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "expiresIn": 300, // Seconds
  "expiresAt": 1726219018607 // Milliseconds since epoch
}

403 Forbidden  TokenExpiredError

If the refresh token used to refresh the authentication token has expired, the response will contain a TokenExpiredError with a status code of 403.

{
  "name": "TokenExpiredError",
  "message": "jwt expired"
}

Example:

const tokenResponse = await relayBox.auth.tokenRefresh();

auth.getSession()

Asynchronous function to return the session data for the logged in user

const result = await relayBox.auth.getSession({
  verify: false
});
OptionsDescriptionType
verify

Verify session data: If true, an HTTP request will be sent via the auth service to fetch session data directly from source. If false, the session data currently in memory will be returned

boolean

Responses

200 OK 

Returns the session data for the logged in user.

{
    "session": {
        "token": "xxxxx.xxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "refreshToken": "xxxxx.xxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "expiresIn": 300,
        "expiresAt": 1726174042498,
        "destroyAt": 1726177342498,
        "authStorageType": "persist"
    },
    "user": {
        "id": "12345678-1234-1234-1234-123456789012",
        "orgId": "12345678-1234-1234-1234-123456789012",
        "appId": "12345678-1234-1234-1234-123456789012",
        "username": "fringedfudge300",
        "clientId": "0fyWl1VWj8Nx",
        "email": "hello@universe.com",
        "createdAt": "2024-09-10T18:14:48.758Z",
        "updatedAt": "2024-09-12T11:22:30.194Z",
        "verifiedAt": "2024-09-10T18:19:45.952Z",
        "authMfaEnabled": true,
        "blockedAt": null,
        "identities": [
            {
                "id": "12345678-1234-1234-1234-123456789012",
                "provider": "github",
                "providerId": "123456",
                "verifiedAt": "2024-09-10T18:14:48.908"
            },
            {
                "id": "12345678-1234-1234-1234-123456789012",
                "provider": "google",
                "providerId": "123456",
                "verifiedAt": "2024-09-10T20:25:42.719"
            },
            {
                "id": "12345678-1234-1234-1234-123456789012",
                "provider": "email",
                "providerId": null,
                "verifiedAt": "2024-09-10T18:19:45.952"
            }
        ],
        "factors": [
            {
                "id": "12345678-1234-1234-1234-123456789012",
                "type": "totp",
                "verifiedAt": "2024-09-10T18:21:07.231"
            }
        ]
    }
}

403 Forbidden  Forbidden Error

In case of failure, the response will return an HTTP authorizer error.

{
  "statusCode": 403,
  "error": "Forbidden",
  "message": "User is not authorized to access this resource"
}

Example

const authUserSession = await relayBox.auth.getSession({
  verify: true
});

auth.signInWithOAuth()

Synchronous function to initiate user sign in via a 3rd party social identity provider.

relayBox.auth.signInWithOauth({
  provider: 'google | github'
});

// Following successful authentication
relayBox.auth.onAuthEvent('SIGN_IN | MFA_REQUIRED', (session: any) => {
  console.log(session)
})
OptionsDescriptionType
provider

Name of social identity provider: The social identity provider to be used for oauth authentication. Currently, 'google' and 'github' are supported.

string

This action opens a popup window to the social identity provider. The user will be redirected back to the application once authorization is complete.

Either SIGN_IN or MFA_REQUIRED will be emitted to the auth.onAuthEvent() listener along with the relevant data to complete the request.

Example:

relayBox.auth.signInWithOauth({
  provider: 'google | github'
});

auth.mfa.enroll()

Asynchronous function to enroll a user for multi factor authentication.

const response = await relayBox.auth.mfa.enroll({
  type: 'totp'
});
OptionsDescriptionType
typeMFA type: Currently only "totp" is supported.string

Responses

200 OK 

Returns the necessary data for enrolling a user in multi factor authentication.

{
  "id": "12345678-1234-1234-1234-123456789012",
  "type": "totp",
  "secret": "J4GDGXAJBM2UYJKSJ5FCI2TYHBQSO5TD",
  "qrCodeUri": "data:image/png;base64,xxxxxx"
}
AttributeDescriptionType
id

The factor id: Required by auth.challenge() and auth.verify() to authenticate the user

string
typeMFA type: Currently only "totp" is supported.string
secret

MFA secret key: Can be used in place of a QR code to register an authentication device.

string
qrCodeUri

MFA QR code: Base64 encoded image data used by an authenticator app to register a new device.

string

403 Forbidden  DuplicateKeyError

If the user is already enrolled for multi factor authentication, the response will return a DuplicateKeyError.

{
  "name": "DuplicateKeyError",
  "message": "MFA type \"totp\" already verified for user"
}

Example:

const response = await relayBox.auth.mfa.enroll({
  type: 'totp'
});

auth.mfa.challenge()

Asynchronous function to request a multi factor authentication challenge.

const challenge = await relayBox.auth.challenge({
  factorId: 'a7821a11-42a2-494b-abdb-0a26cfa01421'
});
OptionsDescriptionType
factorId

MFA factor ID: The ID of the factor to be verified. This will be in uuid format. The factor ID will be the id returned from mfa.enroll() or can be found in the array of factors in the authUserSession object following sign in.

string (uuid)

Returns

Return value includes the challenge id and the verify method. The verify method is the final step in the multi factor authentication process. It accepts an authenticator app code as a parameter and returns an authUserSession object.

{
  id: challenge.id,
  verify: ({ code }) => Promise<AuthUserSession>;
};

Responses

200 OK

Returns the challenge id and expirty time in milliseconds since the epoch.

{
  "id": "12345678-1234-1234-1234-123456789012",
  "expiresAt": 1726234496406
}

400 Bad Request   SchemaValidationError

Request schema validation errors follow a distinct structure across all auth endpoints providing feedback on the fields that failed validation.

{
  "name": "SchemaValidationError",
  "message": "Schema validation failed",
  "data": [
    {
      "validation": "uuid",
      "code": "invalid_string",
      "message": "Invalid uuid",
      "path": [
        "factorId"
      ]
    }
  ]
}

403 Forbidden  ValidationError

If the factor id is invalid, the response will return a ValidationError.

{
  "name": "ValidationError",
  "message": "Invalid factor id"
}

Example:

const mfaEnrollResponse = await relayBox.auth.mfa.enroll({
  type: 'totp'
});

const response = await relayBox.auth.mfa.challenge({
  factorId: mfaEnrollResponse.id
});

auth.mfa.verify()

Asynchronous function to verify a user's multi factor authentication factor challenge.

const response = await relayBox.auth.verify({
  factorId: 'a7821a11-42a2-494b-abdb-0a26cfa01421',
  challengeId: 'a7821a11-42a2-494b-abdb-0a26cfa01421',
  code: '123456',
  autoChallenge: false
});
OptionsDescriptionType
factorIdMFA factor ID: The identifier of the factor to be verified.string
challengeId (conditional)

Short lived challenge ID: The id of the specfic challenge to be verified. Condition: Required if autoChallenge is false.

string
codeSix digit code: The time sensitive code from an authenticator app.string
autoChallenge (optional)

Automatic challenge creation: If true, a challenge will be automatically created on the server when the verify request is recieved. In this scenario, a challenge id is not required.

string

Responses

200 OK  AuthUserSession

{
  "session": {
    "token": "xxxxx.xxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "refreshToken": "xxxxx.xxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "expiresIn": 300,
    "expiresAt": 1726174042498,
    "destroyAt": 1726177342498,
    "authStorageType": "persist"
  },
  "user": {
    "id": "af8f910e-c72c-4335-a104-48212ad65c1f",
    "orgId": "8f6a2232-63e2-4ff7-969f-417739d155ed",
    "appId": "675e81c4-2b88-4167-a33b-0d564d2548a5",
    "username": "fringedfudge300",
    "clientId": "0fyWl1VWj8Nx",
    "email": "hello@universe.com",
    "createdAt": "2024-09-10T18:14:48.758Z",
    "updatedAt": "2024-09-12T11:22:30.194Z",
    "verifiedAt": "2024-09-10T18:19:45.952Z",
    "authMfaEnabled": true,
    "blockedAt": null,
    "identities": [
      {
        "id": "654e6295-6927-4ce2-98b1-dca79a868f05",
        "provider": "github",
        "providerId": "123456",
        "verifiedAt": "2024-09-10T18:14:48.908"
      },
      {
        "id": "fc7c67c7-315d-4bfd-8ae3-8e58bc36d4ae",
        "provider": "google",
        "providerId": "123456",
        "verifiedAt": "2024-09-10T20:25:42.719"
      },
      {
        "id": "55734265-ba2a-4cf8-b41b-3cd63d097a04",
        "provider": "email",
        "providerId": null,
        "verifiedAt": "2024-09-10T18:19:45.952"
      }
    ],
    "factors": [
      {
        "id": "0aa7af26-3313-40ae-9857-24ae66ea939e",
        "type": "totp",
        "verifiedAt": "2024-09-10T18:21:07.231"
      }
    ]
  }
}

403 Forbidden  ValidationError

When an invalid factor id is provided, the response will return a 403 ValidationError.

{
  "name": "ValidationError",
  "message": "Invalid mfa factor id"
}

403 Forbidden  ValidationError

When an invalid factor id is provided, the response will return a 403 ValidationError.

{
  "name": "ValidationError",
  "message": "Unable to verify mfa code"
}

400 Bad Request   SchemaValidationError

Request schema validation errors follow a distinct structure across all auth endpoints providing feedback on the fields that failed validation.

{
  "data": [
    {
      "code": "invalid_type",
      "expected": "string",
      "received": "undefined",
      "path": [
        "factorId"
      ],
      "message": "Required"
    }
  ],
  "name": "SchemaValidationError",
  "message": "Schema validation failed"
}

403 Forbidden  ForbiddenError

When the challenge has expired, the response will return a 403 ForbiddenError.

{
  "statusCode": 403,
  "error": "Forbidden",
  "message": "User is not authorized to access this resource"
}

400 Bad request  ValidationError

If neither a challengeId or autoChallenge is provided, the response will return a 400 ValidationError.

{
  "name": "ValidationError",
  "message": "\"challengeId\" or \"autoChallenge\" required"
}

Example:

// MFA verify with auto challenge
const session = await relayBox.auth.mfa.verify({
  factorId: '12345678-1234-1234-1234-123456789012',
  code: '123456',
  autoChallenge: true
});

// MFA verify with challenge id
const session = await relayBox.auth.mfa.verify({
  factorId: '12345678-1234-1234-1234-123456789012',
  challengeId: '12345678-1234-1234-1234-123456789012',
  code: '123456'
});

// MFA verify with challenge return values
const challenge = relayBox.auth.mfa.challenge({
  factorId: '12345678-1234-1234-1234-123456789012'
})

const response = challenge.verify({
  code: '123456'
})

    On this page