# Card-Based Consent using the Mastercard UI
source: https://developer.mastercard.com/consent-management/documentation/tutorials-and-guides/auth-consent-ui/index.md

## Overview {#overview}

This tutorial uses the reference app to embed the Mastercard Consent Management \& Enrollment UI in your application. The hosted UI captures card-based consent and enrolls cards into Mastercard services without requiring your organization to handle PAN data directly. Use this approach if your organization is not PCI-compliant.

For an overview of the enrollment flow from the cardholder's perspective, see [Consent using Mastercard Consent Management \& Enrollment UI](https://developer.mastercard.com/consent-management/documentation/use-cases/transaction-notifications/single-card-enrolment/card-auth-consent-ui/index.md).

The source code is available in both Java and Python. Download the reference app from the [Reference App](https://developer.mastercard.com/consent-management/documentation/developer-tools/reference-app/index.md) page.

The tutorial walks through the full integration: generating a [signed JWT](https://developer.mastercard.com/consent-management/documentation/tutorials-and-guides/auth-consent-ui/index.md#jwt-creation), [loading the hosted UI script](https://developer.mastercard.com/consent-management/documentation/tutorials-and-guides/auth-consent-ui/index.md#include-consentuijs), and [handling callback messages](https://developer.mastercard.com/consent-management/documentation/tutorials-and-guides/auth-consent-ui/create-user-consents/index.md#consent-flow-result) from the consent flow.

## Prerequisites {#prerequisites}

* Java 17+
* Apache Maven 3.3+
* Python 3.6+
* pip

For both languages, you also need:

* A [Mastercard Developers](https://developer.mastercard.com/dashboard) account with a project that includes the Consent Management \& Enrollment APIs
* OAuth signing key (`.p12`) and consumer key from your project

For detailed setup steps, see the [Quick Start Guide](https://developer.mastercard.com/consent-management/documentation/quick-start-guide/index.md).

## Application Configuration {#application-configuration}

1. Download the reference app from the [Reference App](https://developer.mastercard.com/consent-management/documentation/developer-tools/reference-app/index.md) page.

2. Copy your `.p12` file to `src/main/resources`.

3. Update `src/main/resources/application.properties`:

   ```properties
   signing.consumerKey=<your consumer key>
   signing.pkcs12KeyFile=<your .p12 filename>
   signing.keyAlias=<your key alias>
   signing.keyPassword=<your keystore password>

   ui.consent.url=https://sandbox.consents.mastercard.com
   ui.consent.callback=http://localhost:8081/
   ```

1. Download the reference app from the [Reference App](https://developer.mastercard.com/consent-management/documentation/developer-tools/reference-app/index.md) page.

2. Copy your `.p12` file to `app/config/`.

3. Update `app/config/application.properties`:

   ```properties
   signing.consumerKey=<your consumer key>
   signing.pkcs12KeyFile=<your .p12 filename>
   signing.keyAlias=<your key alias>
   signing.keyPassword=<your keystore password>

   ui.consent.url=https://sandbox.consents.mastercard.com
   ui.consent.callback=http://localhost:8081/
   ```

The `ui.consent.url` property sets the base URL for the hosted UI. Use `https://sandbox.consents.mastercard.com` for Sandbox and `https://consents.mastercard.com` for Production.

The `ui.consent.callback` property sets the URL where the consent flow iframe posts callback messages to your application.
Note: In a production application, store keys and passwords securely, for example in an HSM.

## Build and Run {#build-and-run}

* Java
* Python

```java
mvn clean compile
mvn spring-boot:run
```

```bash
pip3 install -r requirements.txt
FLASK_APP=app/main python3 -m flask run -p 8081
```

Open <http://localhost:8081> in your browser. The home page displays three API cards. Select **Consent Management UI** to launch the hosted UI.

![Reference app home page showing the Consent Management UI card](https://static.developer.mastercard.com/content/consent-management/img/ref-app-home.png)

To walk through the consent flow using this demo, go to [Create User Consents](https://developer.mastercard.com/consent-management/documentation/tutorials-and-guides/auth-consent-ui/create-user-consents/index.md).

## Integration Guide {#integration-guide}

The following sections explain how the reference app implements each part of the integration. No code changes are required to run the reference app. Use these sections as a guide when building the same integration into your own application.

### JWT Creation {#jwt-creation}

When a user navigates to the consent UI page, your server generates a signed JWT and passes it to the frontend template. The JWT authenticates the session with the Mastercard-hosted UI. The token must be generated server-side because it requires your private key.

You can use any JWT library to create and sign the token. The reference app generates a new token on each page load in the `/consents-ui` controller:

#### Header {#header}

The JWT header requires three fields:

|  Name   |   Type   |                 Description                  |      Notes       |
|---------|----------|----------------------------------------------|------------------|
| **typ** | `String` | The type of token.                           | Must be `JWT`.   |
| **alg** | `String` | The algorithm for securing the token.        | Must be `RS256`. |
| **kid** | `String` | The consumer key from Mastercard Developers. |                  |

* JSON

```JSON
{
  "typ": "JWT",
  "alg": "RS256",
  "kid": "XXXXXXXXX!XXXXXXXXXXXXXXXXX0000000000000000"
}
```

#### Payload {#payload}

The JWT payload requires the following fields:

|          Name           |    Type    |                                  Description                                   |
|-------------------------|------------|--------------------------------------------------------------------------------|
| **exp**                 | `DateTime` | Expiration time. Must be within 15 minutes of starting the consent flow.       |
| **iat**                 | `DateTime` | Issued at. The time the JWT was issued.                                        |
| **jti**                 | `String`   | JWT ID. A unique identifier for the token.                                     |
| **nbf**                 | `DateTime` | Not before. The time before which the JWT must not be accepted for processing. |
| **appdata**             | `Object`   | Application data.                                                              |
| **appdata.callbackURL** | `String`   | The URL where the consent flow iframe posts messages to your application.      |

* JSON

```JSON
{
  "exp": 1583760792,
  "iat": 1583758992,
  "jti": "cb",
  "nbf": 1583758992,
  "appdata": {
    "callbackURL": "http://localhost:8081/"
  }
}
```

#### Sign the Token {#sign-the-token}

Sign the JWT using the private key (`.p12` file) from Mastercard Developers.
* Java
* Python

```java
// UIService.java

  private PrivateKey loadSigningKey()
    throws IOException, KeyStoreException, CertificateException,
           NoSuchAlgorithmException, UnrecoverableKeyException {

    KeyStore keystore = KeyStore.getInstance("PKCS12");
    File file = ResourceUtils.getFile(
      ResourceUtils.CLASSPATH_URL_PREFIX + pkcs12KeyFile);
    InputStream readStream = new FileInputStream(
      ResourceUtils.getFile(file.toString()));
    keystore.load(readStream, keyPassword.toCharArray());
    return (PrivateKey) keystore.getKey(keyAlias, keyPassword.toCharArray());
  }

  public String createConsentUIToken(String callbackUrl)
    throws IOException, KeyStoreException, CertificateException,
           NoSuchAlgorithmException, UnrecoverableKeyException {
    PrivateKey privateKey = loadSigningKey();

    HashMap<String, String> appData = new HashMap<>();
    appData.put("callbackURL", callbackUrl);

    Date now = new Date();
    Date validity = new Date(now.getTime() + 1000 * 60 * 15); // 15 minutes

    Claims claims = Jwts.claims();
    claims.setIssuedAt(now);
    claims.setNotBefore(now);
    claims.setExpiration(validity);
    claims.setId("cb");
    claims.put("appdata", appData);

    return Jwts.builder()
      .setHeaderParam("typ", "JWT")
      .setHeaderParam("kid", consumerKey)
      .setClaims(claims)
      .signWith(SignatureAlgorithm.RS256, privateKey)
      .compact();
  }
```

```python
# config.py

def jwt_token():
    now = datetime.now(tz=timezone.utc)
    expire = now + timedelta(minutes=15)
    app_data = {}

    callback_url = configs.get("ui.consent.callback").data
    if len(callback_url) > 0:
        app_data["callbackURL"] = callback_url

    claims = {
        "iat": now,
        "nbf": now,
        "exp": expire,
        "appdata": app_data,
        "jti": "cb"
    }

    jwt_header = {
        "kid": CONSUMER_KEY,
        "typ": "JWT",
        "alg": "RS256",
    }

    with open(SIGNING_P12_FILE, "rb") as f:
        private_key, _, _ = pkcs12.load_key_and_certificates(
            f.read(), KEYSTORE_PASSWORD.encode())

        encoded_jwt = jwt.encode(
            claims, private_key, headers=jwt_header)

        return encoded_jwt
```

For additional JWT examples and a token debugger, see [jwt.io](https://jwt.io/).

### Include ConsentUI.js {#include-consentuijs}

The reference app loads the `ConsentUI.js` script from the hosted UI base URL configured in `ui.consent.url`, then initializes the `ConsentUI` object with the signed JWT.

The `ConsentUI` constructor accepts the following properties:

|   Property    |    Type    |                                   Description                                   |
|---------------|------------|---------------------------------------------------------------------------------|
| **container** | `String`   | CSS selector for the HTML element where the iframe is rendered.                 |
| **jwt**       | `String`   | The signed JWT token generated by your server.                                  |
| **src**       | `String`   | The hosted UI base URL (`https://sandbox.consents.mastercard.com` for Sandbox). |
| **callback**  | `Function` | A function that receives messages from the consent flow iframe.                 |

* Java
* Python

```java
// consent-ui.html (Thymeleaf)

<script type="text/javascript"
    th:src="|${consentUrl}/js/ConsentUI.js|"></script>
<script th:inline="javascript">
  let consentUI = new ConsentUI({
    container: ".consent-ui",
    jwt: /*[[${jwtToken}]]*/ '',
    src: /*[[${consentUrl}]]*/ '',
    callback: callbackUI
  });

  function callbackUI(msg) {
    const pretty = JSON.stringify(msg, undefined, 4);
    console.log("Consent UI message received:\n" + pretty);

    if (msg.type === "Close" || msg.type === "Cancel") {
      consentUI.close();
    }
  }
</script>

<div class="consent-ui" style="width: 500px; height: 800px;"></div>
```

```python
{# consent-ui.html (Jinja2) #}

<script type="text/javascript"
    src="{{ consent_url }}/js/ConsentUI.js"></script>
<script>
  let consentUI = new ConsentUI({
    container: ".consent-ui",
    jwt: "{{ jwt_token }}",
    src: "{{ consent_url }}",
    callback: callbackUI
  });

  function callbackUI(msg) {
    const pretty = JSON.stringify(msg, undefined, 4);
    console.log("Consent UI message received:\n" + pretty);

    if (msg.type === "Close" || msg.type === "Cancel") {
      consentUI.close();
    }
  }
</script>

<div class="consent-ui" style="width: 500px; height: 800px;"></div>
```

The hosted UI is rendered inside the `consent-ui` container element. When the cardholder completes or cancels the flow, call `consentUI.close()` to remove the iframe.
