Cosmic Module

O

Qubits of DPK

March 20, 2026

Core Open Source

The Analogy

Security in Fineract is like a bank's entrance procedure:
  1. #
    Guard at door — checks if you have valid ID (authentication)
  2. #
    Role on your badge — teller, manager, auditor (authorisation)
  3. #
    Separate floors — each bank client can only see their floor (multi-tenancy isolation)

Authentication — Who Are You?

Basic Authentication (Current Default)

Every API request must include a Base64-encoded username:password in the Authorization header:
javascript
QUBITS OF DPK
1Authorization: Basic bWlmb3M6cGFzc3dvcmQ=
2             ―――――― base64("mifos:password") ――――――
Default dev credentials: mifos / password

How Spring Security Processes It

javascript
QUBITS OF DPK
1HTTP Request
2    |
34 TenantAwareBasicAuthenticationFilterCustom filter (runs first)
5    | 1. Reads Fineract-Platform-TenantId header
6    | 2. Loads tenant from fineract_tenants DB
7    | 3. Sets ThreadLocal tenant context
8    |
910 BasicAuthenticationFilter (Spring standard)
11    | 1. Decodes Authorization header
12    | 2. Extracts username + password
13    | 3. Calls FineractUserDetailsService
14    |
1516 FineractUserDetailsService.loadUserByUsername()
17    | 1. Queries m_appuser table in TENANT's schema
18    | 2. Returns AppUser with roles and permissions
19    |
2021 SecurityContextHolder.setAuthentication(user)
22    |User is now authenticated for this request

DB Table: m_appuser

sql
QUBITS OF DPK
1CREATE TABLE m_appuser (
2    id            BIGINT PRIMARY KEY,
3    office_id     BIGINT,
4    username      VARCHAR(100) UNIQUE,
5    password      VARCHAR(255),   -- BCrypt hashed
6    firstname     VARCHAR(100),
7    lastname      VARCHAR(100),
8    is_deleted    BOOLEAN,
9    is_disabled   BOOLEAN
10);
Passwords are stored as BCrypt hashes, never plain text:
java
QUBITS OF DPK
1passwordEncoder.encode("password") 
2// → "$2a$10$hhPPbzaJpHHNE.nmLWnQg.fXgr5rvpT8Tqkdxh..."

Authorisation — What Can You Do?

Role-Based Access Control (RBAC)

Fineract uses a permission system:
  • AppUser has one or more Roles
  • Each Role has a set of Permissions
  • Each Permission maps to ONE API action
javascript
QUBITS OF DPK
1AppUser: "loan_officer_john"
2    └── Role: "Loan Officer"
3            ├── Permission: "READ_LOAN"
4            ├── Permission: "CREATE_LOAN"
5            ├── Permission: "APPROVE_LOAN"
6            └── Permission: "READ_CLIENT"

Permission Naming Convention

javascript
QUBITS OF DPK
1{ACTION}_{ENTITY}
2
3READ_LOANGET /loans
4CREATE_LOANPOST /loans
5APPROVE_LOANPOST /loans/{id}?command=approve
6DISBURSE_LOANPOST /loans/{id}?command=disburse
7DELETE_CLIENTDELETE /clients/{id}

How Permission is Checked in Code

java
QUBITS OF DPK
1// In the API resource (controller)
2@GET
3@Path("{loanId}")
4public String retrieveLoan(@PathParam("loanId") Long loanId) {
5    // This annotation-style check:
6    this.context.authenticatedUser().validateHasReadPermission("LOAN");
7    // Throws ForbiddenException if user lacks READ_LOAN
8    ...
9}

Super User

The mifos account is a super user with all permissions. For production, dedicated role-restricted accounts should be created.

Spring Security Filter Chain

javascript
QUBITS OF DPK
1RequestFilter 1Filter 2Filter 3...Controller
2
3Actual filters in order:
41. TenantAwareBasicAuthenticationFilter  (Fineract custom)
52. BasicAuthenticationFilter             (Spring standard)
63. CorsFilter                            (handles CORS headers)
74. ExceptionTranslationFilter            (converts auth errors to 401/403)
85. FilterSecurityInterceptor             (checks method-level permissions)

Spring Authorization Server — FINERACT-1984 (OAuth 2.1)

What Is It?

Fineract has integrated Spring Authorization Server (SAS) as an alternative to Basic Auth. This enables OAuth 2.1 / JWT tokens.

The Flow

javascript
QUBITS OF DPK
11. Client sends: POST /oauth/token
2                 grant_type=password&username=mifos&password=password
3
42. Fineract SAS validates credentials
5Issues JWT access token (expires in 1 hour)
6Issues refresh token (expires in 7 days)
7
83. Client sends subsequent requests:
9   Authorization: Bearer eyJhbGciOiJSUzI1NiJ9...
10
114. Fineract validates JWT signature, extracts claims (user, tenant, roles)
125. Processes request

Why OAuth over Basic Auth?

This is directly relevant to your GSoC proposal FINERACT-2439! The BFF (Backend for Frontend) would use Spring Authorization Server to issue JWT tokens to mobile/web consumers.

Two-Factor Authentication (2FA)

Fineract has optional 2FA for the web UI:
  1. #
    User logs in with username/password
  2. #
    OTP sent to registered mobile number
  3. #
    User submits OTP
  4. #
    Session established
Handled by fineract-twofactor module.

HTTPS — Encrypted Communication

All Fineract API calls go over HTTPS (port 8443). In local dev, a self-signed certificate is used, so you need -k in curl to skip certificate validation:
bash
QUBITS OF DPK
1curl -k -u mifos:password https://localhost:8443/fineract-provider/api/v1/clients
2#    ―― skip SSL cert check for self-signed cert

Instance Mode Security

This is what your PR #5658 tests. Fineract can run in restricted modes:
java
QUBITS OF DPK
1// Read-only instance: only GET requests allowed
2// Write-only instance: POST/PUT/DELETE allowed, no scheduler jobs
3// Batch-only instance: only scheduler jobs, no API
4
5@Configuration
6public class InstanceModeApiFilter implements Filter {
7    @Override
8    public void doFilter(request, response, chain) {
9        if (isReadOnlyMode && isWriteRequest(request)) {
10            response.sendError(405, "Method Not Allowed in read-only mode");
11            return;
12        }
13        chain.doFilter(request, response);
14    }
15}

Mentor Cheat Sheet