Multi-Factor Authentication
Add an extra layer of security to your account with Multi-Factor Authentication (MFA).
Supported MFA Methods
Section titled “Supported MFA Methods”| Method | Type | Description |
|---|---|---|
| Authenticator App | totp | Time-based codes from apps like Google Authenticator, Authy |
email | Verification codes sent to your email |
Enrolling MFA
Section titled “Enrolling MFA”To enable MFA on your account, first enroll a factor, then verify it.
Step 1: Start Enrollment
Section titled “Step 1: Start Enrollment”POST /auth/mfa/enroll
Section titled “POST /auth/mfa/enroll”Starts enrollment of a new MFA factor. Requires JWT authentication.
Request:
{ "type": "totp"}| Field | Type | Description |
|---|---|---|
type | string | Factor type: totp or email |
Response (TOTP):
{ "factorId": "fac_abc123", "type": "totp", "qrCode": "data:image/png;base64,iVBORw0KGgo...", "secret": "JBSWY3DPEHPK3PXP", "challengeId": "chl_abc123"}| Field | Type | Description |
|---|---|---|
factorId | string | The new factor ID |
type | string | Factor type |
qrCode | string | QR code image (data URL) for authenticator apps |
secret | string | Manual entry code if QR scanning unavailable |
challengeId | string | Challenge ID for verification step |
Step 2: Verify Enrollment
Section titled “Step 2: Verify Enrollment”POST /auth/mfa/verify-enrollment
Section titled “POST /auth/mfa/verify-enrollment”Completes MFA enrollment by verifying the first code.
Request:
{ "challengeId": "chl_abc123", "code": "123456"}| Field | Type | Required | Description |
|---|---|---|---|
challengeId | string | Yes | Challenge ID from enrollment |
code | string | Yes | 6-digit code from authenticator app |
Response:
{ "success": true, "message": "MFA factor enrolled successfully"}Managing MFA Factors
Section titled “Managing MFA Factors”List Enrolled Factors
Section titled “List Enrolled Factors”GET /auth/mfa/factors
Section titled “GET /auth/mfa/factors”Lists all enrolled MFA factors. Requires JWT authentication.
Response:
{ "factors": [ { "id": "fac_abc123", "type": "totp", "createdAt": "2024-01-15T10:00:00Z" }, { "id": "fac_def456", "type": "email", "createdAt": "2024-01-10T08:00:00Z" } ]}Remove a Factor
Section titled “Remove a Factor”DELETE /auth/mfa/factors/{factorId}
Section titled “DELETE /auth/mfa/factors/{factorId}”Removes an MFA factor. Requires JWT authentication.
Response: 204 No Content
MFA During Login
Section titled “MFA During Login”When MFA is enabled and you log in, you’ll receive an MfaRequired status with available factors.
Login Response with MFA
Section titled “Login Response with MFA”{ "status": "MfaRequired", "pendingInfo": { "pendingAuthenticationToken": "pat_abc123...", "availableFactors": [ { "id": "fac_abc123", "type": "totp" }, { "id": "fac_def456", "type": "email" } ], "challenge": { "id": "chl_abc123", "factorId": "fac_abc123", "expiresAt": "2024-01-15T10:05:00Z" } }}Create MFA Challenge
Section titled “Create MFA Challenge”POST /auth/mfa/challenge
Section titled “POST /auth/mfa/challenge”Creates a new MFA challenge for a specific factor.
Request:
{ "factorId": "fac_abc123"}Response:
{ "challengeId": "chl_xyz789", "expiresAt": "2024-01-15T10:05:00Z"}Verify MFA Code
Section titled “Verify MFA Code”POST /auth/mfa/verify
Section titled “POST /auth/mfa/verify”Verifies the MFA code during login to complete authentication.
Request:
{ "pendingAuthenticationToken": "pat_abc123...", "challengeId": "chl_xyz789", "code": "123456"}| Field | Type | Required | Description |
|---|---|---|---|
pendingAuthenticationToken | string | Yes | Token from login response |
challengeId | string | Yes | Challenge ID |
code | string | Yes | 6-digit verification code |
Response:
{ "accessToken": "eyJhbGci...", "refreshToken": "rt_abc123...", "expiresIn": 3600, "userId": "usr_abc123", "email": "john@example.com", "name": "John Doe", "avatarUrl": null, "personalOrgId": "org_abc123", "permissions": ["database:read", "database:write"], "roles": ["member"]}Complete MFA Login Flow
Section titled “Complete MFA Login Flow”// 1. Attempt loginvar loginResult = await client.Auth.LoginWithPasswordAsync( new PasswordLoginRequest( Email: "john@example.com", Password: "SecurePassword123!" ));
if (loginResult.Value.Status == PasswordLoginStatus.MfaRequired){ var pendingInfo = loginResult.Value.PendingInfo!;
// 2. Get the code from user's authenticator app Console.Write("Enter MFA code: "); var code = Console.ReadLine();
// 3. Verify MFA var mfaResult = await client.Auth.VerifyMfaAsync( new MfaVerifyRequest( PendingAuthenticationToken: pendingInfo.PendingAuthenticationToken, ChallengeId: pendingInfo.Challenge!.Id, Code: code ) );
if (mfaResult.IsSuccess) { client.SetAccessToken(mfaResult.Value.AccessToken); Console.WriteLine("Login successful!"); }}async function loginWithMfa(email, password) { // 1. Attempt login const loginResponse = await fetch('https://api.terrascale.io/auth/password', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }) });
const loginData = await loginResponse.json();
if (loginData.status === 'MfaRequired') { // 2. Prompt user for MFA code const code = prompt('Enter your MFA code:');
// 3. Verify MFA const mfaResponse = await fetch('https://api.terrascale.io/auth/mfa/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ pendingAuthenticationToken: loginData.pendingInfo.pendingAuthenticationToken, challengeId: loginData.pendingInfo.challenge.id, code: code }) });
return await mfaResponse.json(); }
return loginData.authResponse;}Next Steps
Section titled “Next Steps”- Authentication - Authentication methods overview
- Dashboard Security Settings - Manage MFA from the dashboard
- Account Login - Login flow documentation