Overview
The End-User Module provides citizens with secure self-service access to their digital identity and documents. Authentication leverages Hyperledger Indy verifiable credentials for privacy-preserving, cryptographically secure login without passwords.Indy Authentication
Passwordless login using verifiable credential proofs
Self-Registration
Email-verified registration with optional TOTP MFA
Access Requests
Approve or reject issuer access requests
Document Access
View and download personal documents from Fabric ledger
Security & Authentication
Role Required:ROLE_USER
Access Paths:
/user/**- User dashboard and features/login/user- Login UI/register/user- Registration flow
- Hyperledger Indy Present-Proof 2.0 - Verifiable credential presentation
- Multi-Factor Authentication - Optional TOTP or email OTP
- Email Verification - OTP-based email confirmation during registration
- Password Recovery - Secure forgot-password workflow
Registration Flow
User Self-Registration
Citizens can register for platform access if they have an existing person record created by an administrator.Important: Registration does NOT create a new person record. The person must already exist in the system (created via Admin module). Registration creates a user account (
users table) linked to the existing person.- Form:
GET /register/user - Submit:
POST /register/user
UserRegistrationController (src/main/java/co/edu/unbosque/ccdigital/controller/UserRegistrationController.java)
Service: UserRegistrationFlowService
Access Registration Form
Navigate to
/register/user to display the registration form.Controller: UserRegistrationController (UserRegistrationController.java:77)Fill Registration Data
Provide required information:
- ID type and number (must match existing person)
- First and last name
- Email address
- Password (with strong validation)
- Optional: Enable TOTP multi-factor authentication
UserRegisterFormEmail Verification
System sends OTP code to provided email address.Configuration:
- Code length:
APP_SECURITY_REGISTER_EMAIL_OTP_CODE_LENGTH - TTL:
APP_SECURITY_REGISTER_EMAIL_OTP_CODE_TTL_MINUTES - Max attempts:
APP_SECURITY_REGISTER_EMAIL_OTP_MAX_ATTEMPTS - Resend cooldown:
APP_SECURITY_REGISTER_EMAIL_OTP_RESEND_COOLDOWN_SECONDS
Confirm Email OTP
Enter the OTP code received via email to verify email ownership.Endpoint:
POST /register/user/email-otp/resendController: UserRegistrationController (UserRegistrationController.java:109)Optional TOTP Setup
If TOTP was enabled during registration:
- QR code is displayed for authenticator app
- Enter TOTP code to confirm setup
POST /register/user/totp/confirmController: UserRegistrationController (UserRegistrationController.java:95)Registration Requirements
Person Linkage:- Person record must exist in
personstable - ID type and number must match exactly
- Person cannot already have a linked user account
- Strong password requirements enforced
- Normalization and validation by
UserRegistrationFlowService
- Email must be unique across users
- Verified via OTP before account creation
- After successful registration, active state synced to Indy
- Enables immediate credential-based authentication
Authentication Flow
The end-user authentication system uses Hyperledger Indy Present-Proof 2.0 protocol instead of traditional passwords.Indy-Based Login
Endpoints:- UI:
GET /login/user - Start proof:
POST /user/auth/start - Poll proof:
GET /user/auth/poll - Verify OTP:
POST /user/auth/otp/verify - Resend OTP:
POST /user/auth/otp/resend
IndyProofLoginService- Proof request and verificationUserAuthFlowService- Complete authentication orchestration
Initiate Login
User accesses
/login/user login page.System calls POST /user/auth/start to initiate proof request.Present-Proof Request
Backend creates present-proof 2.0 request via ACA-Py:Required Attributes:
id_type- ID document typeid_number- ID document numberfirst_name- First namelast_name- Last nameemail- Email address
IndyProofLoginService using IndyAdminClientUser Presents Credential
User scans QR code or uses deep link to present credential from mobile wallet.Frontend polls
GET /user/auth/poll to check proof status.Configuration:- Poll interval:
ACAPY_PROOF_POLL_INTERVAL_MS - Poll timeout:
ACAPY_PROOF_POLL_TIMEOUT_MS
Verify Proof
ACA-Py verifies the presented proof:
- Validates credential signature
- Checks credential hasn’t been revoked
- Extracts verified attributes
IndyProofLoginService#extractVerifiedAttributesSecond Factor (MFA)
If user has TOTP or email OTP enabled, second factor is required:TOTP Configuration:
- Issuer:
APP_SECURITY_TOTP_ISSUER - Digits:
APP_SECURITY_TOTP_CODE_DIGITS - Period:
APP_SECURITY_TOTP_PERIOD_SECONDS - Window:
APP_SECURITY_TOTP_WINDOW_STEPS
- Code length:
APP_SECURITY_LOGIN_OTP_CODE_LENGTH - TTL:
APP_SECURITY_LOGIN_OTP_CODE_TTL_MINUTES - Max attempts:
APP_SECURITY_LOGIN_OTP_MAX_ATTEMPTS - Resend cooldown:
APP_SECURITY_LOGIN_OTP_RESEND_COOLDOWN_SECONDS
Authentication Architecture
Key Components:- IndyAdminClient - ACA-Py admin API integration
- IndyProofLoginService - Proof request lifecycle management
- UserAuthFlowService - Complete authentication orchestration
- UserAccessGovernanceService - Access state synchronization
- IndyUserPrincipal - Security principal with verified attributes
- No Password Storage: System never stores or transmits passwords for Indy login
- Cryptographic Verification: Proof verification via zero-knowledge proofs
- Revocation Checking: Credentials can be revoked at issuer level
- Rate Limiting: Sensitive endpoints protected by
SensitiveEndpointRateLimitFilter - Session Management: Configurable timeout with keepalive/expire endpoints
User Dashboard
After successful authentication, users access their personal dashboard. Endpoint:GET /user/dashboard
Controller: UserController (src/main/java/co/edu/unbosque/ccdigital/controller/UserController.java:56)
Dashboard Features
Personal Information Display
Personal Information Display
Dashboard shows verified attributes from Indy credential:
- Display name (first + last name)
- ID type and number
- Email address
- TOTP MFA status (enabled/disabled, confirmation timestamp)
IndyUserPrincipal from authentication contextDocument List from Fabric
Document List from Fabric
User’s documents are queried directly from Hyperledger Fabric ledger:Service:
FabricLedgerCliService#listDocsViewScript: Calls Node.js script configured via FABRIC_LIST_DOCS_SCRIPTParameters: User’s ID type and ID numberDocuments displayed include:- Document ID and type
- Issue date and expiry date
- Current status
- Blockchain reference for traceability
UserController (UserController.java:63)Access Request Management
Access Request Management
Users can view and manage access requests from issuers:Endpoint:
GET /user/requests (referenced in README.md:170)Actions:- View pending access requests
- Approve requests to grant issuer access
- Reject requests to deny access
- View request history and status
access_requeststable stores request metadataaccess_request_itemslinks specific documentsconsentstable tracks approval/rejection decisions
Document Viewing
Document Viewing
View and download approved documents:Endpoints:
- View:
GET /user/docs/view/{docId}(README.md:171) - Download:
GET /user/docs/download/{docId}(README.md:171)
- Signed URLs with TTL (via
SignedUrlService) - Path validation against allowed directories
- Access event logging to Fabric audit trail
- Secret:
APP_SECURITY_SIGNED_URLS_SECRET - TTL:
APP_SECURITY_SIGNED_URLS_TTL_SECONDS
TOTP Management
Endpoint Base:/user/mfa/totp/* (README.md:172)
Features:
- Enable/disable TOTP authentication
- Regenerate TOTP secret
- View QR code for authenticator apps
- Confirm TOTP setup with test code
- Compliant with RFC 6238 (TOTP)
- Compatible with Google Authenticator, Authy, etc.
- Configurable code length, period, and window
Password Recovery
Endpoint Base:/user/auth/forgot/* (README.md:173)
Flow:
Send Recovery Code
System sends OTP code via email.Configuration:
- Code length:
APP_SECURITY_FORGOT_PASSWORD_CODE_LENGTH - TTL:
APP_SECURITY_FORGOT_PASSWORD_CODE_TTL_MINUTES - Max attempts:
APP_SECURITY_FORGOT_PASSWORD_MAX_ATTEMPTS - Resend cooldown:
APP_SECURITY_FORGOT_PASSWORD_RESEND_COOLDOWN_SECONDS - Mail from:
FORGOT_PASSWORD_MAIL_FROM
Password recovery only applies to the initial registration password. Indy-based authentication does not use passwords after initial setup.
Access Request Workflow
End users control which issuers can access their documents through the access request approval system.Approval Process
Review Request Details
User reviews:
- Requesting entity information
- Which documents are requested
- Purpose of access (if provided)
- Validity period
Approve or Reject
User decides to grant or deny access.Approval:
- Request status changes to
APROBADA - Consent record created in
consentstable - Issuer can view/download approved documents
- Access events logged to blockchain
- Request status reflects rejection
- Issuer cannot access documents
- User can provide rejection reason
Consent Management
Users maintain full control over document access:- Granular Control: Approve/reject specific documents, not all-or-nothing
- Time-Limited: Access requests can have validity periods
- Revocable: Users can revoke previously granted access
- Auditable: All access tracked in blockchain audit trail
Data Privacy & Security
Personal Data Protection
Minimal Disclosure
Indy proofs reveal only required attributes, nothing more
No Password Storage
Credential-based auth eliminates password breach risk
User Consent
Explicit approval required for all document access
Audit Trail
Complete access history in immutable blockchain ledger
Security Headers & Policies
Configured in:SecurityConfig
- Content Security Policy (CSP): Prevents XSS attacks
- HSTS: Enforces HTTPS connections
- X-Frame-Options: Prevents clickjacking (same-origin only)
- Referrer-Policy: Controls referrer information disclosure
- Rate Limiting: Protects against brute force attacks
Session Security
- Inactivity Timeout: Configurable via
SERVER_SESSION_TIMEOUT - Server-Side Sessions: Session data stored securely on server
- Keepalive Endpoint: Prevents timeout during active use
- Explicit Expiration: Session expire endpoint for logout
Endpoint Reference
| HTTP Method | Endpoint | Description | Source |
|---|---|---|---|
GET | /register/user | Registration form | UserRegistrationController.java:77 |
POST | /register/user | Submit registration | UserRegistrationController.java:86 |
POST | /register/user/totp/confirm | Confirm TOTP setup | UserRegistrationController.java:95 |
POST | /register/user/email-otp/resend | Resend email OTP | UserRegistrationController.java:109 |
GET | /login/user | Login UI | README.md:167 |
POST | /user/auth/start | Start Indy proof | README.md:168 |
GET | /user/auth/poll | Poll proof status | README.md:168 |
POST | /user/auth/otp/verify | Verify MFA OTP | README.md:168 |
POST | /user/auth/otp/resend | Resend MFA OTP | README.md:168 |
GET | /user/dashboard | User dashboard | UserController.java:56 |
GET | /user/requests | Access requests | README.md:170 |
GET | /user/docs/view/{docId} | View document | README.md:171 |
GET | /user/docs/download/{docId} | Download document | README.md:171 |
* | /user/mfa/totp/* | TOTP management | README.md:172 |
* | /user/auth/forgot/* | Password recovery | README.md:173 |
Configuration
Key environment variables for the end-user module:Best Practices
- Enable TOTP: Always enable TOTP for enhanced security
- Review Requests Carefully: Check issuer identity before approving access
- Monitor Access: Regularly review access request history
- Secure Email: Use a secure email account for OTP delivery
- Keep Credentials Safe: Protect mobile wallet and authenticator app
- Report Issues: Contact administrators for suspicious activity
Troubleshooting
Cannot Login with Credential
Possible Causes:- Access state is SUSPENDED or DISABLED
- Credential has been revoked by issuer
- ACA-Py agents are not connected
- Credential definition mismatch
- Contact administrator to check access state
- Verify credential in mobile wallet is valid
- Ensure network connectivity for proof exchange
Email OTP Not Received
Possible Causes:- Email in spam/junk folder
- SMTP configuration issue
- Email address typo during registration
- Check spam folder
- Use resend OTP functionality
- Contact support if persistent
TOTP Code Rejected
Possible Causes:- Time synchronization issue
- Wrong authenticator app entry
- Code expired (30-second window)
- Ensure device time is synchronized
- Re-scan QR code to set up authenticator
- Generate fresh code and try again
Related Modules
- Admin Module - Person creation and access state management
- Issuer Module - Access request creation and document upload
