Skip to main content

Authenticator App Setup

Overview

Complete guide for setting up Time-based One-Time Password (TOTP) authenticator apps for two-factor authentication.

Supported Authenticator Apps

  • Google Authenticator (iOS, Android)
  • Microsoft Authenticator (iOS, Android)
  • Authy (iOS, Android, Desktop)
  • LastPass Authenticator
  • 1Password
  • Any RFC 6238 compliant authenticator

Setup Process

Step 1: Initiate Login with Authenticator Method

Call the login endpoint with verificationMethodType=3:

POST /api/BPMSelfService/commands/SelfAdminLoginCommand
{
"username": "admin@example.com",
"password": "SecurePassword123!",
"verificationMethodType": 3
}

Step 2: Check Setup Requirement

If authenticator is not set up, the response will include:

{
"status": "success",
"message": "Authenticator setup required",
"data": {
"requiresSetup": true,
"qrCodeUrl": "otpauth://totp/BankLingo:admin@example.com?secret=ABC123XYZ&issuer=BankLingo",
"secretKey": "ABC123XYZ"
}
}

Step 3: Display QR Code

Present the QR code to the user. You can:

  1. Use a QR code library to generate from qrCodeUrl
  2. Display secretKey for manual entry
  3. Provide both options for flexibility

Step 4: User Scans QR Code

User opens their authenticator app and:

  1. Taps "Add account" or "+"
  2. Selects "Scan QR code"
  3. Scans the displayed QR code
  4. Sees "BankLingo - admin@example.com" entry in app

Step 5: Verify Setup

User enters the 6-digit code from their authenticator app:

POST /api/BPMSelfService/commands/SelfAdminLoginCommand
{
"username": "admin@example.com",
"password": "SecurePassword123!",
"verificationMethodType": 3,
"setupVerificationCode": "123456"
}

Step 6: Setup Complete

On successful verification:

{
"status": "success",
"message": "Login successful",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "...",
"expiresIn": 3600
}
}

The secret key is now saved to the user's account for future logins.

Session Management

Abandoned Setup Handling

If a user starts the authenticator setup but doesn't complete it, the system automatically handles this scenario.

Resuming a Setup Session

When a user returns after abandoning setup (within 24 hours), the system will:

  • Return the same QR code and secret key
  • Allow completion with already-scanned QR code
  • Include isResumedSession: true in response
{
"status": "success",
"message": "Previous authenticator setup session found. Please use the QR code you scanned earlier, or scan this one again.",
"data": {
"requiresSetup": true,
"isResumedSession": true,
"qrCodeUrl": "otpauth://totp/BankLingo:admin@example.com?secret=ABC123XYZ&issuer=BankLingo",
"secretKey": "ABC123XYZ",
"setupStartedAt": "2025-12-25T10:30:00Z"
}
}

User Experience Benefits:

  • ✅ No need to rescan QR code if already scanned
  • ✅ Codes from previously scanned QR code will work
  • ✅ Seamless continuation of setup process

Session Timeout (24 Hours)

If a user returns after 24 hours, the system will:

  • Generate a new secret key and QR code
  • Clear the old setup session
  • Include sessionExpired: true in response
{
"status": "success",
"message": "Your previous authenticator setup session expired after 24 hours. Please scan this new QR code.",
"data": {
"requiresSetup": true,
"sessionExpired": true,
"qrCodeUrl": "otpauth://totp/BankLingo:admin@example.com?secret=NEW456DEF&issuer=BankLingo",
"secretKey": "NEW456DEF",
"previousSessionExpiredAt": "2025-12-24T10:30:00Z"
}
}

Security Rationale:

  • ✅ Old QR codes expire automatically
  • ✅ Prevents indefinite pending setup sessions
  • ✅ Encourages users to complete setup promptly

Switching Authentication Methods

Users can switch between authentication methods during login:

Scenario 1: Authenticator → Email/SMS OTP

If a user starts authenticator setup but then switches to email/SMS OTP:

  • Abandoned authenticator session is automatically cleared
  • Email/SMS OTP works normally
  • No manual cleanup required

Scenario 2: Email/SMS → Authenticator

If a user starts with email/SMS OTP but then switches to authenticator:

  • System detects the change
  • Generates new authenticator QR code
  • Previous email/SMS OTP request is superseded

Frontend Implementation

React Example (with Session Management)

import QRCode from 'qrcode.react';

function AuthenticatorSetup({ qrCodeUrl, secretKey, onComplete }) {
const [code, setCode] = useState('');
const [error, setError] = useState('');

const handleVerify = async () => {
try {
const response = await fetch('/api/BPMSelfService/commands/SelfAdminLoginCommand', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: currentUser.username,
password: currentUser.password,
verificationMethodType: 3,
setupVerificationCode: code
})
});

const result = await response.json();
if (result.status === 'success') {
onComplete(result.data.token);
} else {
setError('Invalid code. Please try again.');
}
} catch (err) {
setError('Setup failed. Please try again.');
}
};

return (
<div>
<h2>Set Up Authenticator App</h2>

<div className="qr-code">
<QRCode value={qrCodeUrl} size={256} />
</div>

<div className="manual-entry">
<p>Or enter this code manually:</p>
<code>{secretKey}</code>
</div>

<div className="verification">
<input
type="text"
placeholder="Enter 6-digit code"
value={code}
onChange={(e) => setCode(e.target.value)}
maxLength={6}
/>
<button onClick={handleVerify}>Verify</button>
</div>

{error && <div className="error">{error}</div>}
</div>
);
}

C# WPF Example

Code Removed

Implementation details removed for security.

Contact support for implementation guidance.

QR Code Format

The qrCodeUrl follows the standard otpauth:// URI format:

otpauth://totp/{Issuer}:{Account}?secret={Secret}&issuer={Issuer}

Example:

otpauth://totp/BankLingo:admin@example.com?secret=ABC123XYZ789&issuer=BankLingo

URI Components

  • Protocol: otpauth://totp/ (Time-based OTP)
  • Issuer: BankLingo (appears in authenticator app)
  • Account: User's email or username
  • Secret: Base32-encoded secret key (160-bit)
  • Issuer parameter: Redundant but recommended for compatibility

Technical Details

Secret Key

  • Length: 160 bits (20 bytes)
  • Encoding: Base32
  • Format: 32 characters (A-Z, 2-7)
  • Storage: Encrypted in database (UserSecurity.TwoFASecretKey)

TOTP Algorithm

  • Standard: RFC 6238
  • Hash: HMAC-SHA1
  • Digits: 6
  • Period: 30 seconds
  • Time Window: ±1 period (±30 seconds)

Security Considerations

Backup and Recovery

  1. Backup codes: Provide one-time backup codes
  2. Multiple devices: Allow registering multiple authenticators
  3. Recovery process: Admin-assisted recovery for lost devices

Best Practices

  • ✅ Display both QR code and manual entry option
  • ✅ Validate code immediately after scanning
  • ✅ Store secret key encrypted
  • ✅ Allow user to disable/reset authenticator
  • ✅ Provide clear instructions and support

Troubleshooting

Common Issues

IssueCauseSolution
Code always invalidTime sync issueCheck device time, enable auto time sync
QR code won't scanLow resolution/qualityIncrease QR code size, improve lighting
Setup times outUser took too longRegenerate QR code, start over
Can't find account in appScanning wrong codeVerify correct QR code is displayed
"Session expired" messageReturned after 24+ hoursScan new QR code provided in response
"Previous session found" messageResumed within 24 hoursUse code from previously scanned QR, or rescan
Switched methods but codes don't workMethod conflictComplete setup with one method before switching

What Happens If...?

I started setup but closed the app?

Within 24 hours: Return to login, select authenticator method again. You'll see "Previous setup session found" and can:

  • Enter code from the QR you already scanned, OR
  • Rescan the same QR code (it hasn't changed)

After 24 hours: You'll see "Your previous setup session expired." You must:

  • Scan the NEW QR code provided
  • The old QR code is no longer valid

I scanned the QR but haven't entered the code yet?

No problem! The session is preserved for 24 hours. When you return:

  • Open your authenticator app
  • Find the "BankLingo" entry you scanned earlier
  • Enter the current 6-digit code
  • Setup will complete successfully

I'm getting "Invalid code" errors after resuming?

Check these:

  1. Time sync: Ensure your device's clock is accurate (Settings → Date & Time → Set Automatically)
  2. Correct entry: Make sure you're looking at the "BankLingo" entry in your authenticator app
  3. Session expired: If it's been 24+ hours, you need the new QR code
  4. Code freshness: TOTP codes change every 30 seconds - enter the current code

Time Synchronization

TOTP codes are time-sensitive. Ensure:

  • Device clock is accurate
  • Auto time sync is enabled
  • Time zone is correct
  • NTP is working (for servers)

Implementation Reference

For technical implementation details, see: