All checks were successful
Auto Tag on Version Change / check-version (push) Successful in 3s
159 lines
3.9 KiB
Markdown
159 lines
3.9 KiB
Markdown
# OTP / 2FA Verification
|
|
|
|
Submit a TOTP code to complete login when `two_factor_required` was `true` in the [login response](01-login.md).
|
|
|
|
---
|
|
|
|
## Endpoint
|
|
|
|
```
|
|
POST https://fahipay.mv/api/app/otp/
|
|
```
|
|
|
|
---
|
|
|
|
## Prerequisites
|
|
|
|
- Completed the [login step](01-login.md) and received `two_factor_required: true`
|
|
- The `__Secure-sess` session cookie from the login response must be present
|
|
- A valid TOTP code from the user's authenticator app
|
|
|
|
---
|
|
|
|
## Request
|
|
|
|
**Content-Type:** `multipart/form-data`
|
|
|
|
### Form Fields
|
|
|
|
| Field | Value | Notes |
|
|
|---|---|---|
|
|
| `code` | `123456` | 6-digit TOTP code from the user's authenticator app |
|
|
| `channel` | `totp` | Always `totp` |
|
|
| `action` | `login` | Always `login` for the login flow |
|
|
| `grant_type` | `auth_id` | Always `auth_id` |
|
|
| `lang` | `en` | Always `en` |
|
|
| `version` | `2.0.0` | App version string |
|
|
| `platform` | `BasedBank` | Client identifier (`app` in the original Fahipay app) |
|
|
| `device[available]` | `true` | Same device fields as login — must match |
|
|
| `device[platform]` | `Android` | |
|
|
| `device[uuid]` | `a1b2c3d4e5f60718` | Must be the **same UUID** used in the login request |
|
|
| `device[model]` | `22101320I` | |
|
|
| `device[manufacturer]` | `Xiaomi` | |
|
|
| `device[isVirtual]` | `false` | |
|
|
| `device[serial]` | `unknown` | |
|
|
|
|
> The `device[uuid]` must be identical to the one sent in the login request. The server uses this to tie the OTP challenge to the login attempt.
|
|
|
|
---
|
|
|
|
## curl Example
|
|
|
|
```bash
|
|
curl --request POST \
|
|
--url https://fahipay.mv/api/app/otp/ \
|
|
--compressed \
|
|
--header 'Cookie: __Secure-sess=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
|
|
--header 'accept: application/json' \
|
|
--header 'accept-encoding: gzip, deflate, br' \
|
|
--header 'connection: keep-alive' \
|
|
--header 'user-agent: Mozilla/5.0 (Linux; Android 14; 22101320I Build/AP2A.240905.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.70 Mobile Safari/537.36' \
|
|
--form 'code=123456' \
|
|
--form 'channel=totp' \
|
|
--form 'action=login' \
|
|
--form 'grant_type=auth_id' \
|
|
--form 'lang=en' \
|
|
--form 'version=2.0.0' \
|
|
--form 'platform=BasedBank' \
|
|
--form 'device[available]=true' \
|
|
--form 'device[platform]=Android' \
|
|
--form 'device[uuid]=a1b2c3d4e5f60718' \
|
|
--form 'device[model]=22101320I' \
|
|
--form 'device[manufacturer]=Xiaomi' \
|
|
--form 'device[isVirtual]=false' \
|
|
--form 'device[serial]=unknown'
|
|
```
|
|
|
|
---
|
|
|
|
## Responses
|
|
|
|
### Success
|
|
|
|
```json
|
|
{
|
|
"title": "Success",
|
|
"authID": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
|
"msg": "Code verification successful",
|
|
"type": "success"
|
|
}
|
|
```
|
|
|
|
| Field | Type | Description |
|
|
|---|---|---|
|
|
| `authID` | `string` | 40-char hex token — use as `authid` header for all subsequent requests |
|
|
| `type` | `string` | `"success"` |
|
|
| `msg` | `string` | Human-readable confirmation |
|
|
|
|
---
|
|
|
|
### Failure — Wrong code
|
|
|
|
```json
|
|
{
|
|
"title": "Error",
|
|
"msg": "Invalid OTP code",
|
|
"type": "error"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Failure — Expired / session mismatch
|
|
|
|
```json
|
|
{
|
|
"title": "Error",
|
|
"msg": "Session expired. Please login again.",
|
|
"type": "error"
|
|
}
|
|
```
|
|
|
|
If the session cookie has expired or the UUID does not match, re-run the full login flow from [Step 1](01-login.md).
|
|
|
|
---
|
|
|
|
## TOTP Details
|
|
|
|
Fahipay uses standard RFC 6238 TOTP:
|
|
|
|
| Parameter | Value |
|
|
|---|---|
|
|
| Algorithm | HMAC-SHA1 |
|
|
| Period | 30 seconds |
|
|
| Digits | 6 |
|
|
| Encoding | Base32 secret |
|
|
|
|
The user's TOTP seed is set up during initial Fahipay account creation and is the same secret used in any standard authenticator app (Google Authenticator, Aegis, etc.).
|
|
|
|
---
|
|
|
|
## Storing the Session
|
|
|
|
After receiving `authID`, persist both values for future sessions:
|
|
|
|
| Value | Description |
|
|
|---|---|
|
|
| `authID` | 40-char hex token — send as `authid` header |
|
|
| `__Secure-sess` | Cookie value — send as `Cookie: __Secure-sess=<value>` |
|
|
|
|
On app restart, attempt requests with the stored session before falling back to a full re-login.
|
|
|
|
---
|
|
|
|
|
|
|
|
---
|
|
|
|
[← Login](01-login.md) **Next →** [Profile](03-profile.md)
|