Authentication - CSR/JWT (Production)
This is the certificate setup for the production environment. Use a separate production certificate – the test environment certificate CANNOT be used!
This authentication method is used for the following products:
- Payment API
- Statement API
- Balance API
- qvik EAM
- Payment Request
The Online Payment Page uses HMAC-based authentication → HMAC authentication (production)
Creating the Configuration File
Using the production registration number specified in the bank contract, the configuration file must be created according to the following template. The string at the end of the highlighted line (27.) (example: AB1234) must be replaced with the production registration number.
The production registration number differs from the test registration number used in the test environment! Check your bank contract or ask your bank representative.
The production registration number can be found in the top right corner next to the username on the Raiffeisen Pay Portal:
Please make sure there is no space between the production registration number and the colon!
oid_section = oids
[req ]
default_bits = 2048
prompt = no
default_md = sha512
distinguished_name = dn
req_extensions = req_ext
[ oids ]
apiUserType = 1.2.3.45
[ dn ]
C=HU
ST= Budapest
L= Budapest
O=APIUser
OU=APIUser_OU
emailAddress=admin@yourdomain.com
CN = apiuser@yourdomain.com
[ req_ext ]
subjectAltName = @alt_names
basicConstraints = critical, CA:FALSE
keyUsage = digitalSignature, keyEncipherment
apiUserType = ASN1:UTF8String:PaymentHUB
2.5.4.97 = ASN1:UTF8String:AB1234
[ alt_names ]
DNS.1 = yourdomain.com
| Field | Explanation |
|---|---|
| ST | Enter the county from which the service is used |
| L | Enter the city from which the service is used |
| emailAddress | The email address of the system administrator user who also created the "API user" on the Raiffeisen Pay Portal |
| CN | The value of the Common Name field in the certificate to be issued. By convention: apiuser@yourdomain.com, where yourdomain.com is the company's own website (but another email address can also be used) |
| 2.5.4.97 | Reserved OID, for identifying the organization. The last highlighted 6 digits in the example ASN1:UTF8String:AB1234 must be replaced with the company's registration number (important: no space between the 6 characters and the colon). |
| DNS.1 | Please copy the company's website name here (for forming the SAN – subject alternative name block) |
In the production configuration file, use real company domain name and email address. This information is embedded in the certificate.
Generating the Private Key and CSR File
Creating the private-public key pair and the certificate signing request (CSR) file required for signing the authentication token is essential.
Using the configuration file produced above, the private key and CSR file must be generated using openssl, following the template below:
- Windows
- Linux
openssl genrsa -out key_production.pem 2048
openssl req -new -key key_production.pem -out csr_production.pem -config csr_details_production.txt
openssl genrsa -out key_production.pem 2048
openssl req -new -key key_production.pem -out csr_production.pem -config csr_details_production.txt
Result:
key_production.pem- Private key (for signing JWT token)csr_production.pem- Certificate Signing Request (to be uploaded to RPP)
Generating KID and Uploading the Certificate
1. Uploading CSR to RPP
Log in to the production Raiffeisen Pay Portal: https://payportal.raiffeisen.hu
On the Certificates tab, click the Upload New Certificate Request button.
Select the production CSR file generated in the previous step (csr_production.pem), upload it and give it a name.
Use a descriptive name: "Production API Certificate 2026-01" - this makes it easier to track expiry dates later.
2. Extracting KID and Credentials
After this, the necessary information can be extracted from the RPP portal interface:
- Technical User ID
- x-api-key (API key)
- KID (Key ID) - to be used in JWT token header
The KID (Key ID) value must be used in the kid header field when generating JWT tokens.
NEVER commit the API key or KID to a git repository! Use environment variables or a secrets manager.
Signature structure
The Detached JWS consists of three main components: Header, Payload and Signature. These are detailed below.
1. Header
The header contains the metadata required for signature validation. The header must be composed in JSON format and then Base64URL encoded.
Required fields
| Field | Type | Description |
|---|---|---|
kid | string | Key ID - The unique identifier belonging to the certificate. Can be obtained from the RaiffeisenPay Portal. |
typ | string | Token type - always "JWT" |
alg | string | Signing algorithm - "RS512" (RSA-SHA512) |
iat | integer | Issued At - Unix timestamp in seconds (time of signing) |
jti | string | JWT ID - Unique identifier (UUID v4). A new value must be generated for each API call! |
Header template
{
"kid": "<KID value from the RaiffeisenPay Portal>",
"typ": "JWT",
"alg": "RS512",
"iat": <unix_timestamp>,
"jti": "<uuid_v4>"
}
Header example
{
"kid": "/SN=15349700155842404063/C=HU/L=Budapest/OU=only_for_development_use/CN=p19026_openbanking_-_api_user_certificates",
"typ": "JWT",
"alg": "RS512",
"iat": 1585563716,
"jti": "e395cf5e-0fc4-430b-9f7e-bee20855b475"
}
The kid value can be obtained from the RaiffeisenPay Portal after uploading the certificate.
2. Payload
The payload is the HTTP request body in JSON format. This is the data you sign and send to the server.
:::danger Critical: Formatting consistency The JWS signature is unique to the given header and payload combination. The JSON sent in the HTTP body MUST EXACTLY match the signed payload.
Many JWT libraries remove whitespace and line breaks before signing. If the formatting of the sent body differs from the signed one, the API will reject the request.
Solution: Use the same JSON string for both signing and sending as the HTTP body. :::
Payload example
{
"orderID": "order_123456",
"creditorAccount": "HU96120106590163520000100000",
"transactionAmount": 1000,
"transactionCurrency": "HUF"
}
3. Signature
The signature is the cryptographic fingerprint of the header and payload combination, created with your private key.
Troubleshooting
JWT error codes
| Error code | Problem | Solution |
|---|---|---|
JWT_GENERAL_ERROR | Incorrect JWT assembly or body/payload mismatch | Verify that the HTTP body exactly matches the signed payload |
JWT_CERT_EXPIRED | Expired certificate | Generate and activate a new certificate on the RPP portal |
JWT_CERT_NOT_ACTIVE | Certificate not activated | Activate the certificate on the RPP portal |
JWT_IAT_EXPIRED | The iat timestamp is too old or in the future | Use accurate, current system time |
JWT_JTI_DUPLICATE | Same jti value used twice | Generate a new UUID for each call |
JWT_NOT_EXISTS | Missing x-jws-signature header | Add the Detached JWT to the header |
Common errors
| Error | Cause | Solution |
|---|---|---|
| 401 Unauthorized | Incorrect JWS signature | Check JWS generation and that the body matches the signed payload |
| 401 Unauthorized | Wrong KID | Verify that you are using the correct KID |
| 401 Unauthorized | Expired certificate | Generate and upload a new CSR |
| Invalid signature | Wrong private key | Verify that you are using the private key belonging to the CSR |
Next steps
After CSR setup and KID extraction, Consent creation and approval is still required on the RPP portal.
With the KID in hand, you can now initiate the first production API call.