Field Level Encryption (FLER) is a security feature that ensures sensitive data is protected when transmitted to and from Banked's APIs. This feature is particularly important for handling personal and financial information, providing an additional layer of security beyond standard TLS encryption.
FLER provides end-to-end encryption for sensitive data, ensuring it remains protected even when passing through third-party services.
Overview
The process involves:
- Choose your response protection method (redaction vs encryption)
- Get API credentials and share public keys with Banked
- Fetch Banked's public keys from the JWKS endpoint
- Generate RSA key pairs and manage encryption keys
- Encrypt sensitive data fields before sending requests
- Handle encrypted or redacted responses appropriately
Prerequisites:
- Valid Banked account with API access
Implementation Steps
The implementation can be broken down into the following steps:
Step 1. Choose Response Protection Method
Before starting integration, decide how you want to handle sensitive data in responses:
Method | Use Case | Setup Required |
---|---|---|
Response Redaction | Fields containing sensitive data will be replaced with [REDACTED] | None |
Response Encryption | You need to access sensitive data from responses | Requires RSA public key |
This choice depends on your need to use the fields from the response. If you need to access the sensitive data in responses, choose response encryption
.
Step 2. Get API Credentials
Contact your Banked representative to receive:
- For Partner integrations: New OAuth credentials for generating tokens
- For all integrations: Basic Auth credentials
- For response encryption: Share your RSA public key
Step 3. Get Banked's Public Keys
Banked provides public keys for encryption via a JWKS (JSON Web Key Set) endpoint:
GET https://api.banked.com/.well-known/jwks.json
Response Format
{ "keys": [ { "kty": "RSA", "use": "enc", "alg": "RSA-OAEP-256", "kid": "1654876509", "n": "jbNTpPiCVdm4D-0UEcM9NkbKJk6Ro9eVfgdK8yC0IzBL2k6D6ebB_QyI5dwFiLT3ZZUp1-zQta3o...GB5R3XqD", "e": "AQAB", "bknd.exp": 1666797757, "bnkd.iat": 1664205757 } ] }
The n
parameter contains the full RSA modulus (base64url-encoded). It's truncated here for readability, but the actual response includes the complete value.
Step 4. Generate and Manage Keys
RSA Public Key (for Response Encryption)
Skip this step if you chose response redaction
in Step 1.
An RSA public key is a cryptographic key used in asymmetric encryption. It consists of two parts:
- A public key that can be shared with others
- A private key that must be kept secure
In the context of FLER:
- You generate and keep the private key
- You share the public key with Banked
- Banked uses your public key to encrypt responses
- You use your private key to decrypt the responses
Generating RSA Keys
Generate an RSA key pair using OpenSSL:
# Generate a 2048-bit RSA private key openssl genrsa -out private.pem 2048 # Extract the public key openssl rsa -in private.pem -pubout -out public.pem
Keep your private key secure and never share it. If your private key is compromised, you must generate a new key pair and update your public key with Banked.
Key Requirements
- Key size: 2048 bits minimum
- Format: PEM
- Algorithm: RSA
- Public exponent: 65537 (0x10001)
Content Encryption Keys (CEK)
A Content Encryption Key is a symmetric key used to encrypt the actual data payload.
For each sensitive data object:
- Generate a new CEK
- Encrypt the CEK using Banked's public key
- Use the CEK to encrypt the sensitive data
- Never reuse CEKs between requests
Step 5. Encrypt Sensitive Data
- Identify fields requiring encryption (see Fields Requiring Encryption)
- Encrypt each sensitive field using the process above
- Prefix encrypted field names with
encrypted_
Example Request
// Original { "payee": { "name": "John Doe", "account_number": "12345678", "sort_code": "123456" } } // Encrypted { "encrypted_payee": "eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2R0NNIiwia2lkIjoiMTY1NDg3NjUwOSJ9..." }
Step 6. Handle Responses
Redacted Response
{ "payee": { "name": "[REDACTED]", "account_number": "[REDACTED]", "sort_code": "[REDACTED]" } }
Encrypted Response
- Content-Type:
application/jose
- Format: JWE (JSON Web Encryption)
- Algorithm: RSA-OAEP-256
- Encoding: A256GCM
API Reference
Fields Requiring Encryption
Payment Sessions API
Endpoint | Field | Sensitivity | Request | Response |
---|---|---|---|---|
POST /v2/payment_sessions | payee | high | encrypt | redact/encrypt |
POST /v2/payment_sessions | payer | high | encrypt | redact/encrypt |
POST /v2/payment_sessions | mandate_id | high | encrypt | encrypt |
POST /v2/payment_sessions | mandate | high | encrypt | redact/encrypt |
GET /v2/payment_sessions | payee | high | N/A | redact/encrypt |
GET /v2/payment_sessions | payer | high | N/A | redact/encrypt |
Bank Accounts API
Endpoint | Field | Sensitivity | Request | Response |
---|---|---|---|---|
POST /v2/bank_accounts | name | low | encrypt | redact |
POST /v2/bank_accounts | account_identifier | high | encrypt | redact |
POST /v2/bank_accounts | sort_code | high | encrypt | redact |
POST /v2/bank_accounts | account_number | high | encrypt | redact |
POST /v2/bank_accounts | secondary_identifier | high | encrypt | redact |
Mandates API
Endpoint | Field | Sensitivity | Request | Response |
---|---|---|---|---|
POST /v2/mandates | source | high | encrypt | redact |
POST /v2/mandates | destination | high | encrypt | redact |
POST /v2/mandates | actions.#.source | high | encrypt | redact |
Error Responses
Invalid Encryption Key
HTTP/1.1 422 Unprocessable Entity Content-Type: application/json { "errors": [ { "code": "invalid", "source": "encryption key", "title": "invalid encryption key" } ] }
When receiving this error, fetch a new key from the JWKS endpoint, re-encrypt your payload, and submit a new request.
Code Examples
Go Implementation
package main import ( "crypto/rsa" "fmt" "log" "github.com/lestrrat/go-jwx/jwk" "gopkg.in/square/go-jose.v2" ) // Get Banked's public key func GetJWK() (jwk.Key, *rsa.PublicKey, error) { set, err := jwk.Fetch("https://api.banked.com/.well-known/jwks.json") if err != nil { return nil, nil, err } key := set.Keys[0] r, err := key.Materialize() if err != nil { return nil, nil, err } rk, ok := r.(*rsa.PublicKey) if !ok { return nil, nil, fmt.Errorf("not an RSA Public Key") } return key, rk, nil } // Encrypt sensitive data func Encrypt(b []byte) ([]byte, error) { k, r, err := GetJWK() if err != nil { return nil, err } encrypter, err := jose.NewEncrypter( jose.A256GCM, jose.Recipient{ Algorithm: jose.RSA_OAEP_256, Key: r, KeyID: k.KeyID(), }, nil, ) if err != nil { return nil, err } encrypted, err := encrypter.Encrypt(b) if err != nil { return nil, err } return []byte(encrypted.CompactSerialize()), nil }
Best Practices
- Generate new CEK for each sensitive data object
- Do not reuse CEKs between requests
- Cache public keys and refresh before expiry
- Handle key rotation gracefully
- Implement proper error handling for encryption/decryption failures