Push Notification Integration
This document describes the Firebase Cloud Messaging (FCM) integration for biometric confirmation push notifications in the ms-auth service.
Overview
The push notification system sends real-time notifications to mobile devices when web users initiate actions that require biometric confirmation. This enables secure, cross-device authentication workflows where users can approve sensitive actions using their mobile devices.
Architecture
Components
Notification Service (
internal/services/notification.go)- Handles FCM client initialization
- Manages notification templates and delivery
- Tracks notification status and failures
- Provides audit logging
Database Schema
notificationstable: Tracks sent notifications and delivery statusregistered_devices.fcm_tokencolumn: Stores FCM tokens for each device
Firebase Integration
- Uses Firebase Admin SDK for server-to-server communication
- Supports iOS, Android, and Web Push notifications
- Handles priority levels and platform-specific configurations
Workflow
- Web user initiates sensitive action (payment, document approval, etc.)
- System creates confirmation session in database
- Notification service finds all user devices with FCM tokens
- System generates platform-specific notification templates
- FCM messages sent to all registered devices
- Mobile app receives notification with deep-link data
- User opens app and completes biometric confirmation
- Confirmation status updated and web session completes
Configuration
Environment Variables
# Firebase Configuration
FCM_ENABLED=true
FCM_PROJECT_ID=your-firebase-project-id
FCM_CREDENTIALS_FILE=/etc/secrets/firebase-service-account.jsonFirebase Service Account
- Go to Firebase Console → Project Settings → Service Accounts
- Generate new private key
- Save JSON file as specified in
FCM_CREDENTIALS_FILE - Ensure the service account has "Firebase Admin SDK Administrator" role
Example Service Account JSON
{
"type": "service_account",
"project_id": "your-firebase-project-id",
"private_key_id": "...",
"private_key": "-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----\\n",
"client_email": "firebase-adminsdk-xxxxx@your-project.iam.gserviceaccount.com",
"client_id": "...",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "...",
"universe_domain": "googleapis.com"
}API Endpoints
Update FCM Token
Updates the FCM token for a registered device to enable push notifications.
PUT /api/v1/auth/devices/fcm-token
Authorization: Bearer <access_token>
Content-Type: application/json
{
"deviceId": "device-uuid",
"fcmToken": "fcm-registration-token"
}Response:
{
"success": true,
"message": "FCM token updated successfully"
}Notification Templates
The system supports various notification types with localized templates:
Confirmation Request Types
Payment Approval
- Title: "Action Confirmation Required"
- Body: "Approve payment of {amount} {currency}"
- Deep link: Contains confirmation ID and payment details
Document Approval
- Title: "Action Confirmation Required"
- Body: "Approve document: {documentName}"
- Deep link: Contains document reference
Purchase Order
- Title: "Action Confirmation Required"
- Body: "Approve purchase order from {supplier} ({amount} VND)"
- Deep link: Contains supplier and amount details
User Access
- Title: "Action Confirmation Required"
- Body: "Approve access for user: {username}"
- Deep link: Contains user details
Platform-Specific Configuration
Android
- Channel ID:
biometric_confirmations - Icon:
ic_notification - Color:
#2196F3 - Click Action:
OPEN_CONFIRMATION
iOS (APNS)
- Category:
BIOMETRIC_CONFIRMATION - Action:
CONFIRM_ACTION - Sound:
default
Web Push
- Icons:
/icons/notification-icon.png - Actions: Confirm/Reject buttons
- Require interaction for high priority
Database Schema
Notifications Table
CREATE TABLE notifications (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
device_id VARCHAR(255) REFERENCES registered_devices(id) ON DELETE SET NULL,
confirmation_id VARCHAR(255) REFERENCES confirmation_sessions(id) ON DELETE SET NULL,
notification_type VARCHAR(50) NOT NULL,
title VARCHAR(255) NOT NULL,
body TEXT NOT NULL,
data JSONB,
fcm_message_id VARCHAR(255),
delivery_status VARCHAR(50) NOT NULL DEFAULT 'pending',
error_message TEXT,
sent_at TIMESTAMP WITH TIME ZONE,
delivered_at TIMESTAMP WITH TIME ZONE,
expires_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);FCM Token Column
ALTER TABLE registered_devices ADD COLUMN fcm_token VARCHAR(255);
CREATE INDEX idx_registered_devices_fcm_token ON registered_devices(fcm_token) WHERE fcm_token IS NOT NULL;Client Implementation
Mobile App Integration
FCM Token Registration
// Get FCM token on app start const fcmToken = await messaging().getToken(); // Update token on server await fetch('/api/v1/auth/devices/fcm-token', { method: 'PUT', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ deviceId: deviceId, fcmToken: fcmToken }) });Handle Notification Received
messaging().onMessage(async remoteMessage => { if (remoteMessage.data.type === 'confirmation_request') { // Show in-app notification // Navigate to confirmation screen navigation.navigate('BiometricConfirmation', { confirmationId: remoteMessage.data.confirmationId, actionType: remoteMessage.data.actionType }); } });Handle Background/Quit State
messaging().onNotificationOpenedApp(remoteMessage => { // Handle notification tap when app is in background if (remoteMessage.data.confirmationId) { navigation.navigate('BiometricConfirmation', { confirmationId: remoteMessage.data.confirmationId }); } });
Security Considerations
Token Security
- FCM tokens are stored encrypted in database
- Tokens are rotated automatically by Firebase
- Invalid tokens are cleaned up during send attempts
Message Security
- All notifications include tamperproof confirmation IDs
- Deep link data is validated server-side
- Sensitive data (amounts, names) is included only in display text
Audit Logging
- All notification attempts are logged
- Failed deliveries are tracked and retried
- Security violations logged for suspicious activity
Error Handling
Common Error Scenarios
Invalid FCM Token
- Token expired or unregistered
- Automatic cleanup from database
- User prompted to re-register on next app open
Firebase Service Unavailable
- Notifications queued for retry
- Fallback to email notifications if configured
- Admin alerts for service outages
Device Not Found
- User has no registered devices with FCM tokens
- Silent failure (not an error condition)
- Web UI shows "no mobile devices" message
Monitoring and Analytics
Delivery Metrics
- Notification send rate and success rate
- Device-level delivery statistics
- User engagement metrics (open rates)
Performance Monitoring
- FCM API response times
- Database query performance
- Background job processing times
Alerts
- High failure rates (>10% in 5 minutes)
- Firebase service account issues
- Database connectivity problems
Testing
Development Setup
- Create Firebase test project
- Generate test service account key
- Use Firebase Console to send test messages
- Verify end-to-end flow with test devices
Integration Tests
- Mock FCM client for unit tests
- Test notification template generation
- Verify database state changes
- Validate error handling scenarios
Deployment
Docker Configuration
# Ensure secrets directory exists
RUN mkdir -p /etc/secrets
# Mount service account key
VOLUME /etc/secretsKubernetes Deployment
apiVersion: v1
kind: Secret
metadata:
name: firebase-service-account
type: Opaque
data:
firebase-service-account.json: <base64-encoded-json>
---
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: ms-auth
env:
- name: FCM_ENABLED
value: "true"
- name: FCM_PROJECT_ID
value: "your-project-id"
- name: FCM_CREDENTIALS_FILE
value: "/etc/secrets/firebase-service-account.json"
volumeMounts:
- name: firebase-credentials
mountPath: /etc/secrets
readOnly: true
volumes:
- name: firebase-credentials
secret:
secretName: firebase-service-accountTroubleshooting
Common Issues
Notifications not received
- Check FCM token validity in database
- Verify Firebase project configuration
- Check device network connectivity and app permissions
High failure rates
- Monitor Firebase quotas and limits
- Check service account permissions
- Verify JSON key file format
Performance issues
- Monitor database query performance
- Check FCM API response times
- Optimize notification batching
Debug Commands
# Check FCM token registration
curl -X GET "http://localhost:8080/api/v1/auth/devices" \
-H "Authorization: Bearer $ACCESS_TOKEN"
# Update FCM token manually
curl -X PUT "http://localhost:8080/api/v1/auth/devices/fcm-token" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"deviceId":"device-id","fcmToken":"fcm-token"}'Logs to Monitor
# Notification service initialization
grep "Notification service initialized" /var/log/ms-auth.log
# FCM token updates
grep "FCM token updated" /var/log/ms-auth.log
# Notification delivery
grep "Notification sent successfully" /var/log/ms-auth.log
# Failures
grep "Failed to send" /var/log/ms-auth.log