Developer
PHR (Personal Health Records) - ABHA Login Guide
This guide documents the PHR ABHA (Ayushman Bharat Health Account) login implementation, including the patient app login flow, API endpoints, and integration patterns.
Overview
The patient app supports three ABHA login methods:
- Login with Mobile - OTP sent to registered mobile
- Login with ABHA Address - Password or OTP authentication
- Login with ABHA Number - OTP to 14-digit ABHA number
Architecture
System Components
Authentication Flow Overview
Login Methods
1. Login with Mobile (Section 6.3)
API Endpoints:
| Endpoint | Method | Description |
|---|---|---|
/login/mobile/request_otp | POST | Send OTP to mobile |
/login/mobile/verify_otp | POST | Verify OTP, returns ABHAs |
/login/verify_user | POST | Select ABHA, generate session |
2. Login with ABHA Address (Section 12.1 / Password)
API Endpoints:
| Endpoint | Method | Description |
|---|---|---|
/login/abha_address/search | POST | Get available auth methods |
/login/abha_address/verify_password | POST | Verify with password |
3. Login with ABHA Number (Section 6.2)
Note: ABHA Number login may return "Invalid LoginId" in ABDM sandbox.
API Endpoints:
| Endpoint | Method | Description |
|---|---|---|
/login/abha_number/request_otp | POST | Send OTP to ABHA number |
/login/abha_number/verify_otp | POST | Verify OTP |
API Reference
Common Headers
All PHR API requests must include:
Content-Type: application/json
Authorization: Bearer <gateway_token>
REQUEST-ID: <uuid>
TIMESTAMP: <ISO8601 format>Request Format
{
"abha_address": "john123@sbx",
"password": "Addval@A621"
}Response Format
Success:
{
"success": true,
"data": {
"abha_token": "eyJhbG...",
"abha_refresh_token": "eyJ...",
"abha_expires_in": 1800,
"abha_profile": {
"abha_address": "john123@sbx",
"abha_number": "12-3456-7890-1234",
"name": "John Doe",
"mobile": "9876543210"
},
"kulcare_session": { ... }
}
}Error:
{
"success": false,
"error": "Error message from ABDM or Kulcare"
}Error Codes
| Code | Message | Description |
|---|---|---|
| ABDM-1006 | Invalid LoginId | Invalid ABHA address or number |
| ABDM-1016 | Invalid Timestamp | Request timestamp format incorrect |
| ABDM-9999 | Invalid Password | Password verification failed |
| ABDM-9999 | Invalid ABHA Address | ABHA address format incorrect |
Frontend Implementation
Login Flow State Machine
Component Architecture
Zustand Store Structure
interface PhrOtpState {
method: 'mobile' | 'abha_address' | 'abha_number';
loginId: string;
txnId: string;
abhaToken: string;
abhaList: AbhaAccount[];
otpType?: 'mobile' | 'aadhaar';
}
interface AuthState {
user: User | null;
session: KulcareSession | null;
phrOtpState: PhrOtpState | null;
// ...
phrSignIn: (session: KulcareSession) => void;
setPhrOtpState: (state: PhrOtpState) => void;
clearPhrOtpState: () => void;
}Backend Implementation
Service Architecture
Key Services
GenerateKulcareSessionService
This service creates a Kulcare session from ABHA verification data:
PhrRequest Logging
All outbound API calls are logged to the phr.requests table:
Security Considerations
RSA Encryption
All sensitive data (mobile numbers, OTPs, passwords) must be encrypted using RSA:
Token Handling
- Gateway Token: Obtained from
Phr::FetchGatewayTokenV3for ABDM API calls - ABHA Token: Received from ABDM after successful verification
- Kulcare Session: Generated JWT for authenticated sessions
Data Privacy
- Patient ABHA data is stored with
phone_verified: trueflag - All API requests are logged for audit purposes
- PII is not logged in production
Environment Configuration
Development (Sandbox)
# config/credentials/development.yml
abdm_phr_host: https://abhasbx.abdm.gov.in/abha/api/v3/phr/app
abdm_gateway_host_v3_modes: https://dev.abdm.gov.in/cmProduction
# config/credentials/production.yml
abdm_phr_host: https://phr.abdm.gov.in/api/phr/app/v3
abdm_gateway_host_v3_modes: https://cm.abdm.gov.inKeys
RSA public keys for encryption are stored in:
config/keys/abdm_public_auth_number.pemTesting
API Testing with curl
Search ABHA Address:
curl -X POST http://localhost:3000/phr/login/abha_address/search \
-H "Content-Type: application/json" \
-d '{"abha_address": "john123@sbx"}'Verify Password:
curl -X POST http://localhost:3000/phr/login/abha_address/verify_password \
-H "Content-Type: application/json" \
-d '{"abha_address": "john123@sbx", "password": "your_password"}'Mobile OTP Flow:
# Step 1: Send OTP
curl -X POST http://localhost:3000/phr/login/mobile/request_otp \
-H "Content-Type: application/json" \
-d '{"mobile": "9876543210"}'
# Step 2: Verify OTP
curl -X POST http://localhost:3000/phr/login/mobile/verify_otp \
-H "Content-Type: application/json" \
-d '{"mobile": "9876543210", "otp": "123456", "txn_id": "your_txn_id"}'Troubleshooting
Common Issues
| Issue | Cause | Solution |
|---|---|---|
| "Invalid Timestamp" | Timestamp format incorrect | Use Time.now.utc.iso8601(3) |
| "Missing Credentials" | No Authorization header | Add Bearer <token> header |
| "Invalid Password" | Wrong password or encoding | Check RSA encryption |
| "Invalid ABHA Address" | abhaAddress not encrypted | Only encrypt password, not address |
| 401 Unauthorized | Gateway token expired | Refresh gateway token |
Log Analysis
All PHR API calls are logged in phr.requests table:
SELECT * FROM phr.requests
WHERE action = 'verify_password'
ORDER BY created_at DESC
LIMIT 10;File Structure
Backend
backend/domains/phr/
├── controllers/login/logins_controller.rb
├── routes.rb
├── models/phr_request.rb
├── services/
│ ├── login/
│ │ ├── mobile/
│ │ │ ├── request_otp.rb
│ │ │ └── verify_otp_service.rb
│ │ ├── abha_address/
│ │ │ ├── search_abha_address_service.rb
│ │ │ └── verify_password_service.rb
│ │ └── generate_kulcare_session_service.rb
│ └── abha/
│ └── encrypt_phr_data.rb
└── services/fetch_gateway_token_v3.rbFrontend
patient/src/
├── features/auth/
│ ├── components/
│ │ ├── LoginForm.tsx
│ │ ├── AbhaOtpVerification.tsx
│ │ └── ProtectedRoute.tsx
│ └── schemas/
│ └── abha-login.schema.ts
├── services/
│ └── phr-auth.service.ts
├── stores/
│ └── auth.store.ts
├── types/
│ ├── phr.types.ts
│ └── auth.types.ts
├── constants/
│ ├── api.ts
│ └── routes.ts
└── api/
└── phr-client.ts