Detailed design
Registrant Authentication — Feature Design Document
Project: OpenG2P Registry Gen2 Feature: Registrant Authentication via OIDC/OAuth2.0 Status: Design / Pre-implementation Date: 2026-04-10
1. Overview
Registrant Authentication is a feature that allows staff operating the registry to authenticate a registrant (farmer, disabled person, vehicle owner, etc.) using the same OIDC/OAuth2.0 infrastructure as user login, but designed for in-portal authentication facilitation rather than self-service login.
Key Use Case:
Staff opens a registrant's record in the registry
Staff clicks "Authenticate Registrant" widget
Widget initiates authentication with the configured auth provider (Keycloak, eSignet, etc.)
Auth provider performs authentication (password, OTP, biometric, face, voice, etc.)
Registry verifies the returned token and stores authentication proof
Audit trail is maintained; registrant is notified
Authentication is valid for a configured period (e.g., 2 years)
When approaching expiry, system notifies registrant to re-authenticate
Architectural Key Insight: This feature reuses the IAM service's OIDC/OAuth2.0 core libraries (imported as a dependency) but operates completely independently from user login. Registrant authentication is:
Tied to a registrant record (
internal_record_id), not a user sessionInitiated by staff, not self-service
Stored in the registry database with full audit trail
Managed with explicit expiry and re-authentication workflows
2. Design Principles
Reuse, Don't Duplicate: Import IAM core libraries (OidcClient, token validation, adapters) as a dependency
Separation of Concerns: Registrant auth is entirely separate from user authentication and authorization
Audit First: Every authentication attempt (success/failure) is recorded with full context
Compliance Ready: Stores proof (token hash, claims, method) for verification and audits
Extensible Providers: Pluggable adapter pattern supports any OIDC/OAuth2.0 provider (Keycloak, eSignet, custom)
Graceful Expiry: Clear workflow for re-authentication with user notifications
3. Data Model
3.1 G2PRegistrantAuthenticationProvider
G2PRegistrantAuthenticationProviderConfiguration table for registrant authentication providers. Multiple providers can be active simultaneously, allowing registrants to choose their preferred authentication method.
Location: openg2p-registry-gen2-core/.../models/g2p_registrant_authentication_provider.py
Multi-Provider Support:
Multiple providers can be active for the same register (e.g., Keycloak + eSignet)
Registrant chooses which provider to use via widget dropdown
display_ordercontrols the order in the UI dropdownregister_idallows different registers to have different available providers (or same providers)
3.2 G2PRegistrantAuthentication
G2PRegistrantAuthenticationAudit trail table. Records every authentication attempt (success or failure) for every registrant.
Location: openg2p-registry-gen2-core/.../models/g2p_registrant_authentication.py
Indexes: (register_id, internal_record_id), (internal_record_id, status), (expiry_at) (for finding expired authentications).
3.3 G2PRegisterDefinition Extension
G2PRegisterDefinition ExtensionAdd authentication requirements to register metadata:
3.4 G2PRegisterAuthentication Mixin Base Class
G2PRegisterAuthentication Mixin Base ClassAbstract base class for register types that support authentication. Domain registers opt-in to authentication by extending this mixin.
Location: openg2p-registry-gen2-core/.../models/g2p_register_authentication.py
3.5 Domain Register Extension (Example: Farmer)
Domain registers that require authentication extend both base classes:
Optional Feature:
If a domain register does not need authentication, it only extends
G2PRegisterIf it needs authentication, it extends both
G2PRegisterandG2PRegisterAuthenticationThis separation keeps authentication optional and allows flexibility per domain
Denormalized Fields: These fields in the mixin enable fast queries like "which registrants need re-authentication notifications?" without joining to the G2PRegistrantAuthentication audit table.
4. Service Layer
4.1 G2PRegistrantAuthenticationService
G2PRegistrantAuthenticationServiceOrchestrates the registrant authentication flow with support for multiple providers.
Location: openg2p-registry-gen2-core/.../services/g2p_registrant_authentication_service.py
4.2 Reuse from IAM
Import and wrap IAM core services:
5. Authentication Flow
5.1 Staff Selects Provider and Initiates Authentication
Step 1: Fetch Available Providers
Endpoint: GET /register-data/get-available-authentication-providers
Step 2: Initiate Authentication with Selected Provider
Endpoint: POST /register-data/authenticate-registrant
Flow:
5.2 Auth Provider Callback
Endpoint: GET /registrant-auth/callback?code=...&state=...
6. Adapter Pattern
Registrant authentication adapters are identical to user login adapters in IAM, reused as-is.
6.1 Keycloak Adapter
6.2 e-Signet Adapter
Key Point: These adapters extract authentication_method and claim_verifications — data specific to registrant authentication that user login doesn't need.
7. Controller Service and API Endpoints
7.1 Controller Service
Location: openg2p-registry-gen2-core/.../controller_services/g2p_registrant_authentication_controller_service.py
7.2 Staff Portal API Endpoints
Location: openg2p-registry-gen2-apis/openg2p-registry-staff-portal-api/.../g2p_registrant_authentication_controller.py
8. UI Widget
8.1 Registrant Authentication Widget
Location: openg2p-registry-gen2-ui-widgets/src/widgets/RegistrantAuthenticationWidget.tsx
A new React widget for the staff portal with provider selection:
UI Example:
8.2 Registrant Authentication Status Widget
Display current auth status:
9. Notification and Re-authentication Workflow
9.1 Periodic Re-authentication Check
Celery Beat Producer: registrant_authentication_expiry_beat_producer
Every hour, query for registrants approaching expiry:
9.2 Notification to Registrant
Celery Worker: registrant_authentication_expiry_notifier
Sends notification (SMS, email, push) to registrant:
10. Configuration
10.1 Registry Configuration
Add to G2PRegisterDefinition:
10.2 Provider Configuration
Set up multiple G2PRegistrantAuthenticationProvider records (one per authentication option):
Example 1: Keycloak (Password + OTP)
Example 2: eSignet (Biometric)
Multi-Provider Flexibility:
Different registers can have different available providers
Registrants choose their preferred authentication method
Providers are sorted by
display_orderin the UICan enable/disable providers independently via
is_activeflag
10.3 Environment Variables
11. Encryption and Security
11.1 User Claims Storage
User claims are encrypted at rest:
Uses a master encryption key managed via environment or KeyVault.
11.2 Token Hash (Proof, Not Storage)
Instead of storing the actual token, store a SHA-256 hash:
Purpose: Proof that authentication was performed, not for validation. Allows auditing without exposing the original token.
11.3 Security Features Reused from IAM
PKCE: Protects authorization code interception
Nonce: Prevents ID token replay attacks
State Parameter: Prevents CSRF
at_hash: Verifies access token integrity
HTTPS only: Secure cookie transmission
Token validation: Signature verification via JWKS
12. Audit Trail Features
The G2PRegistrantAuthentication table provides:
Who:
initiated_by_staff_id(which staff initiated)When:
initiated_at,completed_at,created_atWhat:
user_claims(who was authenticated),authentication_method(how)Proof:
token_hash(hash of original token)Verification:
claim_verifications(what was verified)Status:
status(success/failure),failure_reasonValidity:
token_expires_at,expiry_at(when auth is no longer valid)
Compliance Benefits:
Non-repudiation: Staff can't deny initiating authentication
Evidence: Token hash proves token was received and validated
Auditability: Full timeline of every authentication attempt
Traceability: Links staff, registrant, provider, method
13. Comparison: User Login vs. Registrant Authentication
Who
System user (staff, agent)
Beneficiary/registrant
Where
Login portal, self-service
Initiated by staff in-app
Why
Access the system
Prove identity for record
Storage
Secure HTTP-only cookie
Database record + encrypted
Lifespan
Session (hours)
Long-term (2 years)
Expiry
Implicit (session timeout)
Explicit, with warnings
Audit
User access logs
Authentication audit trail
Adapter
LoginProvider
RegistrantAuthenticationProvider
Reuse
OidcClient, token validation
OidcClient, token validation, adapters
13. Database Migrations
New Tables (Alembic migrations):
[ ]
g2p_registrant_authentication_providers(provider configuration)[ ]
g2p_registrant_authentications(audit trail)
Updated Tables: For each domain register that supports authentication, add columns via migration:
last_authentication_id(FK)last_authenticated_at(DateTime)last_authentication_status(String enum)authentication_expiry_at(DateTime, indexed)authentication_expiry_notified(Boolean)
Example: When G2PRegisterFarmer extends G2PRegisterAuthentication, the g2p_register_farmers table automatically includes these columns.
14. Implementation Checklist
Core Service Layer:
[ ] Create models:
[ ]
G2PRegistrantAuthenticationProvider(provider config)[ ]
G2PRegistrantAuthentication(audit trail table)[ ]
G2PRegisterAuthentication(mixin base class)
[ ] Create service:
G2PRegistrantAuthenticationService[ ] Create controller service:
G2PRegistrantAuthenticationControllerService[ ] Wrap IAM libraries: OidcClient, token validation, adapters
[ ] Implement AuthenticationSession (state/nonce/code_verifier, TTL)
[ ] Encryption/decryption for user_claims
API Endpoints (Staff Portal):
[ ]
POST /register-data/authenticate-registrant/initiate[ ]
GET /registrant-auth/callback[ ]
POST /register-data/get-registrant-authentication-status[ ]
POST /register-data/get-registrant-authentication-history
UI Widgets:
[ ]
RegistrantAuthenticationWidget(initiate button + popup)[ ]
RegistrantAuthenticationStatusWidget(display status)
Celery Tasks:
[ ]
registrant_authentication_expiry_beat_producer[ ]
registrant_authentication_expiry_notifier
Migrations:
[ ] Alembic migrations for new tables (providers, authentications)
[ ] Add fields to
G2PRegisterDefinition(authentication requirements)[ ] Add columns to domain registers that extend
G2PRegisterAuthenticationmixinVia inheritance, columns are auto-generated in extending tables
Configuration:
[ ] Setup
G2PRegistrantAuthenticationProvidertable[ ] Create provider record (Keycloak/eSignet)
[ ] Configure register metadata (
requires_registrant_authentication)[ ] Environment variables for encryption key, callback URL
Testing:
[ ] Unit tests for authentication flows
[ ] Integration tests with mock auth provider
[ ] Encryption/decryption tests
[ ] Expiry notification logic
15. Architectural Highlights
Mixin-Based Design
The G2PRegisterAuthentication mixin base class embodies clean architecture principles:
Benefits:
Single Responsibility:
G2PRegisterstays focused on core functionalityOptional Feature: Only registers that need authentication extend the mixin
Consistency: Follows existing mixin pattern (G2PPerson, G2PGeo)
Flexibility: Different domains can choose to support authentication or not
Clean Tables: Database tables only include columns they actually use
Last updated
Was this helpful?