Customer Login
Overview
Authenticate customers (self-service users) using email/username and password with two-factor authentication support. All device and channel context is supplied via HTTP request headers — not the request body.
Endpoint
POST /api/BPMSelfService/commands/SelfLoginCommand
Request Headers
All device identification headers are required for mobile clients and strongly recommended for web clients. They feed into security auditing, session tracking, and device-switch detection.
| Header | Required | Example | Description |
|---|---|---|---|
X-App-Channel | Yes | Mobile / Web | Client channel — defaults to Web if absent |
X-Device-Id | Yes (Mobile) | a1b2c3d4-e5f6-... | Unique device identifier (UUID) |
X-Client-Platform | Recommended | Android / iOS / Chrome | Device OS or browser |
X-App-Version | Recommended | 2.1.0 | App or web client version |
X-Device-Host | Optional | Samsung Galaxy S24 | Device hostname / name |
X-Device-Model | Optional | SM-G991B | Device model code |
X-Ip-Address | Optional | 41.58.12.100 | Client IP (forwarded by gateway) |
X-App-Build-Number | Optional | 210 | App build number |
X-App-Package-Name | Optional | com.bank.app | App package / bundle identifier |
When at least one of X-Device-Host, X-Client-Platform, or X-Device-Model is present, the server stores a full JSON device snapshot in the session. Otherwise it falls back to the plain User-Agent string for backward compatibility.
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
username | string | Yes | Customer username or email |
password | string | Yes | Customer password |
verificationMethodType | integer | No | 2FA method: 0=Default, 1=Email, 2=SMS, 3=Authenticator (default: 0) |
otpCode | string | Conditional | OTP code for email/SMS verification |
setupVerificationCode | string | Conditional | TOTP code for authenticator setup verification |
deviceToken | string | No | Biometric device token — required when activating biometric login for the first time on this device |
Response
Successful Login (with OTP step)
{
"status": "success",
"message": "OTP sent successfully",
"data": {
"otpSent": true,
"maskedEmail": "j***@example.com",
"expiresIn": 300
}
}
Fully Authenticated
{
"status": "success",
"message": "Login successful",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "...",
"expiresIn": 3600
}
}
Device Switch Required (Status 46)
Returned when a mobile user logs in from a device that does not match their registered device and has not yet confirmed the switch. The password was correct — this is a consent prompt, not an error.
{
"ok": true,
"message": "Executed successfully",
"outData": {
"isSuccessful": true,
"statusCode": "46",
"message": "Your credentials have been verified. This device is not your registered device. Would you like to switch to this device?",
"data": {
"requiresDeviceSwitch": true,
"verificationReason": "DEVICE_SWITCH_REQUIRED"
}
}
}
What to do: Show the user a confirmation prompt. If they agree, resend the exact same SelfLoginCommand request with switchDevice: true added to the body. This will trigger OTP verification to complete the device switch.
// Re-call with user consent
body: JSON.stringify({
username: 'customer@example.com',
password: 'SecurePassword123!',
switchDevice: true // ← add this
})
After submitting with switchDevice: true, the server sends an OTP to the user's registered email/phone. Pass the received OTP code back using the standard OTP Validation flow to complete the switch and log in.
statusCode: 46 with isSuccessful: true is intentional — credentials were valid, the server is awaiting explicit consent before proceeding.
Example Usage
const response = await fetch('/api/BPMSelfService/commands/SelfLoginCommand', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-App-Channel': 'Mobile',
'X-Device-Id': '550e8400-e29b-41d4-a716-446655440000',
'X-Client-Platform': 'Android',
'X-App-Version': '2.1.0',
'X-Device-Model': 'SM-G991B'
},
body: JSON.stringify({
username: 'customer@example.com',
password: 'SecurePassword123!'
})
});