# API Basics
source: https://developer.mastercard.com/ob-accept-payments/documentation/api-basics/index.md

## Authentication {#authentication}

Mastercard Open Finance uses [OAuth 2.0 authorization](https://datatracker.ietf.org/doc/html/rfc6749#page-1) framework with [Client Credentials Grant](https://datatracker.ietf.org/doc/html/rfc6749#section-4.4). In this flow, the Integrator needs to authenticate towards the Authorization Server to gain an Access Token that will be used to access the API.

A description of the steps necessary to implement the authentication is detailed below.

### 1: Generate asymmetric cryptography keys {#1-generate-asymmetric-cryptography-keys}

As a pre-requisite, you need to generate an asymmetric cryptography public-private key pair and certificate.

When you authenticate on our authorization server, we want to make sure that only you can obtain access tokens for your clientId. For that we will validate that your requests are signed with a private key that only you have.

At the moment we only support RSA keys. We recommend an RSA key of 4096 bits of length and valid for at least one year. In the future, you will need to provide a new certificate to us before this expires, or face possible downtime in your applications.

#### Example {#example}

For testing, you can use [OpenSSL](https://openssl-library.org/) to generate these.

Write the following in the terminal:

    openssl req -x509 -sha256 -nodes -newkey rsa:4096 -keyout private.key -days 730 -out public.pem

This will create two files:

* private.key: The private key used for signing the JWT.
* public.pem: The public certificate that can be used to verify the JWT.

Note: **Do not share your Private Key.** Store the Private Key securely and use it to sign your JWT token before requesting an access token from us (find more details in the sections below).  
You will need to share the public certificate with us (see below).

In a production environment, we suggest generating the private key in an HSM or similar, exporting the public key and sharing that with us.

### 2: Share the Public Certificate with us {#2-share-the-public-certificate-with-us}

Before you can start using Mastercard Open Finance authentication we need to add your Public Certificate to our list of trusted certificates. Please contact your onboarding officer.
Note: It is important to note that self-signed certificates are only supported in our Sandbox/MTF environment. When you are ready to move to Production, you will need to acquire a certificate from a supported Certificate Authority (CA). For more information, refer to [Moving to Production](https://developer.mastercard.com/ob-accept-payments/documentation/api-basics/index.md#moving-to-production).

After that, you can call the `oauth2/token` endpoint to obtain an access token, necessary to use the Mastercard Open Finance API.
* Sandbox
* Production

```Sandbox
https://mtf.auth.openbanking.mastercard.eu/oauth2/token
```

```Production
https://auth.openbanking.mastercard.eu/oauth2/token
```


API Specification: `https://static.developer.mastercard.com/content/ob-accept-payments/swagger/auth_service_ma_dev_1.yaml`

You will need to populate the `client_assertion` field with a JWT used by the Auth Service for verifying the caller. The details necessary to generate and sign the JWT token are shown below.

### 3: Generate and sign the JWT token {#3-generate-and-sign-the-jwt-token}

##### What is a JWT? {#what-is-a-jwt}

The JSON Web Token (JWT) is an open standard ([RFC7519](https://datatracker.ietf.org/doc/html/rfc7519)) that allows transmitting security information between two parties in a compact way as a JSON object.

In this documentation, we will cover how to generate a JWT with specific claims, sign it using a certificate generated by OpenSSL, and provide a C# example for the implementation.

##### The JWT format {#the-jwt-format}

JWT consists of three parts: a header, a payload, and a signature.

##### The JWT header {#the-jwt-header}

The header specifies the type of token (JWT) and the signing algorithm (RS256).

* "alg": "RS256"
* "typ": "JWT"
* "kid": thumbprint of the certificate used to sign the JWT.

##### The JWT Payload {#the-jwt-payload}

The JWT Payload must have the following claims:

| **Field** |    **Name**     |    **Type**    |                                     **Description**                                      |
|-----------|-----------------|----------------|------------------------------------------------------------------------------------------|
| `sub`     | Subject         | string         | The ID of the client. This is the ID that you receive during onboarding your Integrator. |
| `iss`     | Issuer          | string         | The ID of the client (must be the same value as "Subject").                              |
| `exp`     | Expiration time | Unix timestamp | The expiration time of the JWT. Must be a date in future.                                |
| `aud`     | Audience        | string         | The audience of the JWT. Must be set to "auth.mastercard.com".                           |
| `jti`     | JWT ID          | string         | Must be a unique GUID.                                                                   |

**Example**

```json
JWT Payload
{
  "sub": "<client-id>",
  "iss": "<client-id>",
  "exp": 1723125616,
  "aud": "auth.mastercard.com",
  "jti": "27edbf3f-c5a1-460d-8248-0af06f93200b"
}
```

##### The JWT Signature {#the-jwt-signature}

To understand how this works, you can use [JWT.io](https://jwt.io/) and the pair of public certificate with private key to quickly sign a JWT. Make sure to use the right algorithm (RS256). To sign the JWT, you only need to provide the private key. If you want to validate that the signing went correctly, you can provide the public certificate as well, and you should see the "Signature verified" text.

**Example: Generate JWT and Sign with Private Key using C#**

Below is a C# example for generating a JWT. The signed JWT should then be passed as the client_assertion to the oauth2/token endpoint.
Tip: This code serves to illustrate the core functionality. Make sure to add proper error handling, logging, validation, removing hardcoded values, and unit test it before putting it into production.

```C#
public string CreateJwtToken()
{
    // Create the RSA security key from the private key          
    var privateKey = File.ReadAllText("path/to/your/private.key");

    using var rsa = RSA.Create();
    rsa.ImportFromPem(privateKey);
    var rsaSecurityKey = new RsaSecurityKey(rsa)
    {
        KeyId = GetKidFromCertificate()
    };

    // Define token parameters
    var tokenHandler = new JwtSecurityTokenHandler();

    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(new[]
        {
            new Claim(JwtRegisteredClaimNames.Sub, "<client-id>"),
            new Claim(JwtRegisteredClaimNames.Iss, "<client-id>"),
            new Claim(JwtRegisteredClaimNames.Aud, "auth.mastercard.com"),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
        }),
        Expires = DateTime.UtcNow.AddHours(1),
        SigningCredentials = new SigningCredentials(rsaSecurityKey, SecurityAlgorithms.RsaSha256)
    };

    // Create the JWT token
    var token = tokenHandler.CreateToken(tokenDescriptor);
    return tokenHandler.WriteToken(token);
}
```

The above example calls a private method to add the headers. The implementation could look as follows:

```C#
private static string GetKidFromCertificate()
{
    const string pemCertPath = "path/to/your/certificate.pem";
    var pemContent = File.ReadAllText(pemCertPath);

    // Remove PEM headers/footers and whitespace
    var cleanedPem = pemContent
        .Replace("-----BEGIN CERTIFICATE-----", "")
        .Replace("-----END CERTIFICATE-----", "")
        .Replace("\r", "")
        .Replace("\n", "")
        .Replace(" ", "")
        .Replace("\t", "");

    // Compute SHA-256 hash
    var certBytes = Convert.FromBase64String(cleanedPem);
    var hash = SHA256.HashData(certBytes);

    // Convert to base64url encoding
    var base64 = Convert.ToBase64String(hash);

    return base64.TrimEnd('=')
        .Replace('+', '-')
        .Replace('/', '_');
}
```

### 4: Request an access token {#4-request-an-access-token}

Once you have the JWT token signed, you can call Authentication Service to obtain a Mastercard Open Finance Access Token.

Note that you need to use the following URL for the Authentication Service endpoints:

API Reference: `POST /oauth2/token`

Find below details on how to populate the fields:

|        **Field**        |                                                                                                                                                              **Description**                                                                                                                                                               |
|-------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `grant_type`            | Set to client_credentials grant type.                                                                                                                                                                                                                                                                                                      |
| `client_assertion_type` | Set to JWT Bearer Token assertion type - urn:ietf:params:oauth:client-assertion-type:jwt-bearer                                                                                                                                                                                                                                            |
| `client_assertion`      | Set to the signed JWT bearer token you created previously.                                                                                                                                                                                                                                                                                 |
| `scope`                 | There are four possible values that you can set here - ob_accept_payments, ob_theming, ob_reporting or ob_onboarding. We also support setting multiple scopes. You can do this by passing an array indicating all of the scopes you want to use. Example: "scope": \["ob_theming", "ob_accept_payments", "ob_reporting", "ob_onboarding"\] |

Note: You cannot reuse a JWT after you already used it to obtain an Access Token.

In response, you will receive the following:

|   **Field**    |                                                 **Description**                                                 |
|----------------|-----------------------------------------------------------------------------------------------------------------|
| `access_token` | Set to client_credentials grant type.                                                                           |
| `token_type`   | The type of the Access Token. This is always "bearer".                                                          |
| `expires_in`   | This is the Access Token that you need to use as a bearer token in all API requests to Mastercard Open Finance. |

### 5: Use the access token to access the API {#5-use-the-access-token-to-access-the-api}

Send the Access Token that you received above as a bearer token (Authorization header) in each API request to us to enable us to validate your access.

**Accessing the API example**

    GET /payments/123 HTTP/1.1
    Host: server.example.com
    Content-Type: application/json
    Authorization: Bearer <Access Token>

### Managing the access tokens {#managing-the-access-tokens}

The Access Tokens issued by Mastercard Open Finance have an expiration period. The expiration period is set to 1 hour. Note that this value may change in the future.

Always check the value in `expires_in` property of the received access token to understand the validity period. You will need to generate and sign a new JWT token and request a new Access Token when the current one expires.

### Updating your Keys {#updating-your-keys}

If your Public Certificate is due to expire, or your Private Key has been compromised, you will need to generate a new private-public key pair. For this go through the same steps as above.
Note: Begin signing your JWTs with your new Private Key only after confirmation that your new Public Certificate has been added to our trusted certificates.

### Moving to Production {#moving-to-production}

Once you are ready to make the move from testing in our Sandbox/MTF environment to our Production environment, it is essential that you acquire an SSL/TLS OV certificate from one of our supported Certificate Authorities. Once you have received your certificate, contact your onboarding officer for next steps.

#### Operational guidance (recommended) {#operational-guidance-recommended}

* Plan ahead: issuing an OV certificate can take 2--4 weeks.
* Validity: ensure the certificate has at least 9 months validity remaining at the time of submission.
* Renewal: provide replacement certificates 30--60 days before expiry to avoid service disruption.

#### Supported Certificate Authorities (SSL/TLS OV) {#supported-certificate-authorities-ssltls-ov}

* DigiCert
* GoDaddy
* NETS AS
* VeriSign

<br />

If you also require eIDAS qualified certificates (licensed / PSD2 scenarios):

* Some implementations (for example, operating under your own license) may also require eIDAS qualified certificates. eIDAS qualified certificates can only be issued by a Qualified Trust Service Provider (QTSP). Recommendation
* Prioritize QTSPs that can issue all certificates you need (ideally both SSL/TLS and the required eIDAS certificates) to reduce vendor management and renewal overhead.

#### Indicative provider notes: {#indicative-provider-notes}

* DigiCert: commonly used for SSL/TLS; also offers eIDAS qualified certificate products.
* VeriSign: legacy brand now delivered under DigiCert's certificate portfolio.
* Sectigo: offers SSL/TLS and eIDAS qualified certificate products.
* NETS AS: used for SSL/TLS in some onboarding materials; verify eIDAS qualified issuance capability if required.
* GoDaddy: used for SSL/TLS; if you need eIDAS qualified certificates, verify QTSP issuance capability and scope.

## Environments {#environments}

Early access environment connects to a test bank, intended to assist with the initial integration for new customers. The primary purpose is to enable testing the structure of the request and response messages.

Depending on the region and selected scheme, the test banks may also offer additional functionality, like generic UI flows that simulate Strong Customer Authentication (SCA) with the banks or some advanced scenarios, but are not intended to replicate a full implementation on the bank side. Refer to [Test Banks](https://developer.mastercard.com/ob-accept-payments/documentation/testing-and-integration/test-banks/index.md) for additional details.
Note: Sandbox data is not guaranteed to be persistent over time, as we delete data periodically.

The Production environment provides access to real bank data. For details on how to gain production access, refer to [Production](https://developer.mastercard.com/ob-accept-payments/documentation/production/index.md).
* Sandbox
* Production

```Sandbox
https://mtf.api.openbanking.mastercard.eu/accept-payments
```

```Production
https://api.openbanking.mastercard.eu/accept-payments
```

## Correlation IDs {#correlation-ids}

The API supports hierarchical request IDs through the optional header `X-Correlation-Id`:

    X-Correlation-Id: <your Correlation Id>

This allows tracing calls across systems and is helpful in debugging.

The correlation ID should be unique and must begin with \| and end with `.` Everything in between must be a character (`A-Za-z`), digit (`0-9`), underscore (`_`) or dash (`-`). The maximum length is 128 characters. The correlation ID is returned in every response in the `X-Correlation-Id` header.

Here is an example of a valid Correlation Id:

`|aedRc498c_c7bc4A89ea8cc9Vb-V9c91f0F3cfe.`

## Concurrent Requests {#concurrent-requests}

Aggressive concurrency is supported between parallel sessions (subject to rate limits). Concurrent requests within a single session are not supported.

## Idempotency {#idempotency}

The API supports idempotency on all POST, PUT and PATCH requests if the optional header `X-Request-Id` is in the request:

    X-Request-Id: <your request Id>

Note: It is strongly recommended to use idempotency.

In the event that a network error or similar causes a request to fail, you can retry the request with the same X-Request-Id-header. If we have already processed the request, we will return a cached response and will not actually process the request. In the event that the first request has not yet finished processing, we will return a `HTTP 409 Conflict` to indicate that we cannot process the second request while the first request is ongoing. You can wait for the first request to complete or try the request again.

## Rate Limiting {#rate-limiting}

Rate limiting is applied on all endpoints. That means you can only make a certain number of requests over a certain period of time. The current rate will be displayed in the `X-RateLimit-Limit header`.

The returned HTTP headers of any limited request will show your current rate limit status:

    HTTP/1.1 200 OK 
    Date: Mon, 08 Jul 2019 09:27:06 GMT 
    Status: 200 OK 
    X-RateLimit-Limit: 3000 
    X-RateLimit-Remaining: 37 
    X-RateLimit-Reset: 39 
    { <content> }

|       **Header**        |                           **Description**                            |
|-------------------------|----------------------------------------------------------------------|
| `X-RateLimit-Limit`     | The maximum number of requests you are permitted to make per window. |
| `X-RateLimit-Remaining` | The number of requests remaining in the current rate limit window.   |
| `X-RateLimit-Reset`     | The number of seconds that is left until the limit resets.           |

When you exceed your rate limit, you will receive an HTTP Status = 429 Too Many Requests error response. Refer to [Codes and Formats](https://developer.mastercard.com/ob-accept-payments/documentation/code-and-formats/index.md) for a sample of the error and how to handle it.

## Providers Endpoint {#providers-endpoint}

Do not use the Get Providers endpoint to display bank selection on your side unless you have an outsourcing agreement with us. Please speak to your account manager for more information.

## Paging {#paging}

The endpoints that return a list of results support paging.

These endpoints can be controlled through the query parameters `limit` and`offset`. Limit will ensure that only that number of items are returned. Offset will control how many items will be skipped before returning the results.

`GET /resources?offset=5&limit=5` will return resources 6 to 10.

If a limit is not specified, then the default limit applies.
