Integration Guide – Onemoney Web Redirection Mechanism

Integration Guide – Onemoney Web Redirection Mechanism

Introduction

The Web redirection is a mechanism for FIUs to redirect their users from FIU Web or mobile application to Onemoney AA web application for purpose of user registration, account discovery and linking and consent management and redirection of user back to the FIU web or mobile application. It is a mechanism for seamless and frictionless user experience for end to end consumer journey.

In this mechanism the Onemoney Web application is invoked by FIU application as a HTTP GET request along with some encrypted parameters in the request URL to redirect the consumer from a FIU application page to Onemoney web application. Similarly, once the consumer finishes his activity of approving or rejecting his consent in Onemoney the FIU application is invoked as a HTTP GET request along with some encrypted parameters in the response URL to redirect the consumer from Onemoney web application to a particular page of FIU application.

Process Flow

  • FIU gets the Onemoney AA Webview URL form Central Registry
  • FIU securely captures consumer’s AA Id or VUA in its application if the consumer is already registered with Onemoney AA or his mobile number if the consumer is a new user and does not have a profile with Onemoney AA
  • FIU server generates a consent request (as per ReBIT API specifications) by passing customer VUA in the consent request if the customer is already registered with Onemoney AA or constructs a VUA in mobilenumber@onemoney format if the customer is a new user and not yet registered with Onemoney AA. In response the FIU server receives a consent handle from Onemoney AA server.
Note

Note 1: If the customer is an existing user in Onemoney then Onemoney server will validate the VUA before sending the consent handle in response. If VUA does not exist then an error response “InvalidCustomerAddress” will be returned in response.

Note 2: If the customer is a new user then Onemoney server will validate the structure of VUA that it is in mobilenumber@onemoney format. It will also validate whether any VUA already exists for the given mobile number in the constructed VUA. If either of the validation fails then an error response “InvalidCustomerAddress” will be returned.

  • FIU mobile or web application sends a redirection request to Onemoney web application by constructing a request URL which includes some encrypted parameters, FIU entityId and request date/time.
  • Onemoney AA server on receiving the redirection request URL decrypts the encrypted URL and performs validation.
  • After validation of redirection request Onemoney web application will display the Onemoney login screen or user registration screen depending on whether the customer is existing user or new user.
  • If the customer is existing user of Onemoney then customer will authenticate himself with Onemoney. After successful authentication user will be displayed the consent details. Customer will either approve/reject the consent. Similarly, if the customer is a new user of Onemoney then customer will register himself with Onemoney with his mobile number. Onemoney will authenticate the customer by sending OTP to his mobile number. Once customer is registered he will link his financial accounts with Onemoney. After account linking he will be displayed the consent details which he will either approve/reject.
  • Based on customer’s approval/rejection of consent Onemoney server will send notification to FIU server alongwith a unique ConsentId provided the consent is approved.
  • Onemoney AA will then re-direct the customer to FIU application by constructing a response URL which includes some encrypted parameters, AA Id and response date/time.
  • FIU application on receiving the response URL will decrypt the URL and validate it. After validation FIU will display customer the page of the FIU application where it had asked Onemoney AA to be redirected back.

FIU server will then proceed to check the status of consent. If its approved it will fetch the consent artefact from Onemoney AA server and then proceed to place the data request.

Web Redirection Request Parameters

(FIU Calling AA)

A sample request looks like the following:

Onemoney Web application URL

Sandbox – https://aa-sandbox.onemoney.in/

UAT – https://aa-uat.onemoney.in/

Production – https://aa.onemoney.in/

HTTP Method : GET

The URL parameters are as follows (all mandatory):

Parameter NameParameter TypeParameter Description
ecreqBase 64 encoded stringEncrypted parameters (see below)
reqdateStringreqdate field format will be ddmmyyyyhh24misss in UTC. Expiry of this field will be 180 secs and beyond this request will be invalid
fiStringUnique FIU identifier or FIU entityId. This will be encrypted using Base64/XOR along with reqdate field

ecreq encrypted parameters

Below are the parameters that will be encrypted using AES256 encryption algorithm

Parameter NameParameter TypeParameter Description
txnidStringUUID txnid. Uniquely identifies a particular redirection event. This same value will be returned by AA to FIU in the ecres txnid field.
sessionidStringValue that represents a ‘state’ (or session) on the FIU end. This value is opaque to AA and will be returned as is to the FIU by AA in ecres sessionid field.
useridStringThe AA user Id or handle or VUA generated by AA after a user is registered with AA (Refer to AA Handle below)
redirectStringFIU URL that AA needs to call back after user has provided consent in the AA domain
srcrefStringConsent handle Id, as returned by AA server to the Consent request API invoked by FIU to AA prior to this redirection call

AA Handle

For new AA user

The userid should be in mobilenumber@AA format. If AA is Onemoney it should be mobilenumber@onemoney

For existing AA user

The userid should be AA handle generated by AA during user registration. E.g. 9999999999@onemoney

Web Redirection Response Parameters

(AA Calling FIU)

In the response from the AA back to FIU, below URL parameters would be sent by AA

HTTP Method : GET

The URL parameters are as follows (all mandatory):

Parameter nameParameter typeParameter description
ecresBase64 encoded StringEncrypted parameters (see below)
resdateStringformat will be ddmmyyyyhh24misss UTC
fiStringUnique AA identifier or AA entityId. This will be encrypted using Base64/XOR along with resdate field

ecres encrypted parameters

Below are the parameters that will be encrypted using AES256 encryption algorithm

Parameter nameParameter typeParameter description
txnidStringUUID txnid received in ecreq field in the request
sessionidStringValue of sessionid received in the ‘ecreq’ field in the request.
useridStringThe AA user id or AA handle or VUA
statusStringThe status ‘S’ for success and ‘F’ for failure
errorcodeStringRefer the errorcodes table below
srcrefStringThe consent handle id received in the ecreq ‘srcref’ field

Error codes: The following errorcodes are returned by the AA to FIU when the user is redirected back to the FIU application.

Error codeMessageMandatoryWhen is this returned
0SuccessYWhen the user has accepted the consent
1Consent is rejectedYWhen the user rejects the consent
2Consent not availableYConsent request not found with the AA. It could be due to the consent handle not available with the AA to which the customer is redirected
3Invalid requestYThe redirection request has invalid data

Encryption Mechanism

The mechanism to encrypt the ecreq and acres parameters in the redirection request and response are given below

1. Data-in-transit security by encrypting the communication channel: This is a must-have anyway and TLS 1.2 and above will be used (https), for communication between the FIU app and the AA web app.

2.  Additional Data-in-transit security through encryption of data:

All encryption must be done using AES 256. For the AES 256 encryption below will be used

IV – This can be 0

SALT – This will be the reqdate or resdate

Fi – This will be the unique FIU ID or AA ID ( i.e. the FIU entityId or AA entityId )

SECRETKEY – This will be the secret passphrase shared by the FIU to AA

Reference link: https://mkyong.com/java/java-aes-encryption-and-decryption/

Note: The SECRETKEY will be shared offline between FIU and AA

Sample Code for XOR and encryption of the ecreq and ecres fields.

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Base64.*;
import static javax.crypto.Cipher.DECRYPT_MODE;
import static javax.crypto.Cipher.ENCRYPT_MODE;
public class WebRedirection {
    private static final String AES_ALGO = "AES";
    private static final String KEY_ALGO = "PBKDF2WithHmacSHA256";
    private static final String AES_CBC_PKCS5 = "AES/CBC/PKCS5Padding";
    private static final String secretKey = "ac12ghd75kf75r";
    private static final String fi = "FIUID";

    public static String encrypt(String strToEncrypt, String salt) {
        final byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

        IvParameterSpec ivspec = new IvParameterSpec(iv);

        try {
            SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_ALGO);
            KeySpec spec = new PBEKeySpec(secretKey.toCharArray(), salt.getBytes(), 65536, 256);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), AES_ALGO);
            Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5);
            cipher.init(ENCRYPT_MODE, secretKey, ivspec);
            return getUrlEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes(UTF_8)));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String decrypt(String strToDecrypt, String salt) {
        byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
        IvParameterSpec ivspec = new IvParameterSpec(iv);
        try {
            SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_ALGO);
            KeySpec spec = new PBEKeySpec(secretKey.toCharArray(), salt.getBytes(), 65536, 256);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), AES_ALGO);
            Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5);
            cipher.init(DECRYPT_MODE, secretKey, ivspec);
            return new String(cipher.doFinal(getUrlDecoder().decode(strToDecrypt)));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void printUsage() {
        System.out.println("Usage: java EncryptUtil <salt> <payload>");
        System.out.println("       where, 'reqdate' is to be used as salt & payload is as per the webview URL redirection spec doc.");
        System.out.println("  e.g. java EncryptUtil 031120201803460 \"txnid=T1234&sessionid=S1234&srcref=Srcref1234&userid=acme@perfios-aa&redirect=https://example.com\"");
        System.out.println("");
    }

    public static void main(String[] args) {
        String salt = null;
        String payload = null;


        if (args.length < 2) {
            printUsage();
            return;
        }
        salt = args[0];
        payload = args[1];
        if (salt == null || salt.length() == 0) {
            System.out.println("Error: Salt must not be empty.");
            printUsage();
            return;
        } else {
            System.out.println("Using salt: " + salt);
        }
        if (payload == null || payload.length() == 0) {
            System.out.println("Error: Payload must not be empty.");
            printUsage();
            return;
        }
        System.out.println("Using payload: " + payload);
        String encData = encrypt(payload, salt);

        if (encData != null) {
            System.out.println("Encrypted & encoded data: " + encData);
            System.out.println("Decrypted data (to verify): " + decrypt(encData, salt));
            
            String xoredFI = encryptValueToXor(fi, salt);
            System.out.println("Xored FI: " + xoredFI);
            System.out.println("Xored FI (reversed): " + decryptXoredValue(xoredFI, salt));
        }
    }

    public static byte[] getRandomNonce(int numBytes) {
        byte[] nonce = new byte[numBytes];
        new SecureRandom().nextBytes(nonce);
        return nonce;
    }
    
	



/**
	 * Generate xored output of a using key.
	 * 
	 * @param a
	 * @param key
	 * @return
	 */
    static byte[] xor(byte[] a, byte[] key) {
        byte[] out = new byte[a.length];
        for (int i = 0; i < a.length; i++) {
            out[i] = (byte) (a[i] ^ key[i%key.length]);
        }
        return out;
    }
    
    static String decryptXoredValue(String xoredValue, String key) {
    	return new String(xor(Base64.decode(xoredValue.getBytes(), Base64.NO_WRAP), key.getBytes()));
    }
    
    static String encryptValueToXor(String value, String key) {
    	return new String(Base64.encode(xor(value.getBytes(), key.getBytes()), Base64.NO_WRAP));
    }
}