# Handling 3DS Authentication
source: https://developer.mastercard.com/consent-management/documentation/tutorials-and-guides/card-consents-tutorial/handling-3ds-auth/index.md

## Overview {#overview}

After creating a consent, if 3DS authentication is required, the reference app performs two steps: device fingerprinting and an authentication challenge. This page describes both steps and the API calls involved.

## Consent States {#consent-states}

When a consent is created for a card, its status is set to one of the following values:

|   Status   |                          Description                          |
|------------|---------------------------------------------------------------|
| `APPROVED` | Authentication is not required or has completed successfully. |
| `REQAUTH`  | Authentication is required before the consent is active.      |
| `FAILED`   | Authentication failed.                                        |
| `EXPIRED`  | The consent has passed its validity period.                   |

A card may have the same consent multiple times with different states. This enables consent renewal --- a new consent can be created before an existing one expires without interfering with the active consent.

## Step 1: 3DS Fingerprinting {#step-1-3ds-fingerprinting}

When the `POST /consents` response indicates `auth.type` = `THREEDS`, the reference app renders a fingerprint page. This page opens a hidden iframe that collects browser device information and sends it to the 3DS Access Control Server (ACS).

The fingerprinting page calls the `doFingerprint` JavaScript function:

```javascript
function doFingerprint(threeDsMethodUrl, threeDSMethodNotificationURL,
                       threeDSMethodData, threeDSServerTransID) {
    if (threeDsMethodUrl) {
        // Open hidden iframe to collect browser info and POST to ACS
        const iframe = document.createElement("iframe");
        iframe.style.display = "none";
        document.body.appendChild(iframe);
        // ... iframe POSTs to ACS ...

        // 10-second timeout for fingerprinting delays or ACS non-response
        fingerprintTimeout = setTimeout(() => {
          proceedAfterFingerprint('timeout');
        }, 10000);

        window.addEventListener("message", fingerprintCompleteListener);
    } else {
        // No threeDsMethodUrl --- skip fingerprinting
        proceedAfterFingerprint('unavailable');
    }
}
```

Once fingerprinting completes (or times out), the browser details are collected and posted to the reference app's `/start-3ds-authentication` endpoint:

```javascript
function proceedAfterFingerprint(fingerprintStatus) {
    const params = {
        fingerprintStatus: fingerprintStatus,
        challengeWindowSize: '04', // 600x400
        browserAcceptHeader: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        browserColorDepth: window.screen.colorDepth,
        browserJavaEnabled: true,
        browserLanguage: navigator.language,
        browserScreenHeight: window.screen.height,
        browserScreenWidth: window.screen.width,
        browserTZ: new Date().getTimezoneOffset(),
        browserUserAgent: window.navigator.userAgent,
    }
    post("/start-3ds-authentication", params);
}
```

## Step 2: Start Authentication {#step-2-start-authentication}

The `/start-3ds-authentication` endpoint calls the Consent Management \& Enrollment API `POST /consents/{cardReference}/start-authentication`, passing the browser details collected during fingerprinting.
* Java
* Python

```java
// ConsentsController.java

  @PostMapping("/start-3ds-authentication")
  public String start3dsAuthentication(@RequestParam Map<String, Object> body,
                                       Model model, RedirectAttributes redirectAttrs) {

    StartAuthReq startAuthReq = new StartAuthReq();
    Auth auth = new Auth();
    auth.setParams(body);
    startAuthReq.setAuth(auth);

    try {
      StartAuthResp resp = apiService.getApiClient().startConsentsAuth(cardRef, startAuthReq);

      if (resp.getAuth().getStatus().equals("AUTHENTICATED")) {
        redirectAttrs.addFlashAttribute("authStatus", resp.getAuth().getStatus());
        redirectAttrs.addFlashAttribute("cardRef", cardRef);
        return "redirect:/consents";
      }

      if (resp.getAuth().getStatus().equals("AUTH_FAILED")) {
        model.addAttribute(ERROR_MSG, resp.toString());
        return ERROR_TEMPLATE;
      }

      if (resp.getAuth().getStatus().equals("AUTH_IN_PROGRESS")) {
        model.addAttribute("params", resp.getAuth().getParams());
        return "threeds-challenge";
      }

    } catch (ApiException e) {
      model.addAttribute(ERROR_MSG, e.getResponseBody());
    } catch (Exception e) {
      model.addAttribute(ERROR_MSG, e.getMessage());
    }

    return ERROR_TEMPLATE;
  }
```

```python
@app.route("/start-3ds-authentication", methods=['POST'])
def start_3ds_authentication():

    resp = api_start_authentication(
        session["card_ref"], session["test_card_details"], request.form)

    params = resp["auth"]["params"]
    status = resp["auth"]["status"]

    if status == 'AUTHENTICATED':  # frictionless case
        session['auth_status'] = status
        return redirect(url_for('consents_info'))

    if status == 'AUTH_FAILED':
        error_msg = resp
        return render_template('error.html', error_msg=error_msg)

    return render_template('threeds-challenge.html', **params)
```

### Start Authentication Parameters {#start-authentication-parameters}

The following parameters are passed to `POST /consents/{cardReference}/start-authentication`:

|       Parameter       |                                                   Description                                                   |
|-----------------------|-----------------------------------------------------------------------------------------------------------------|
| `fingerprintStatus`   | Result of fingerprinting: `complete`, `timeout`, or `unavailable`                                               |
| `merchantName`        | Displayed in the challenge iframe                                                                               |
| `browserAcceptHeader` | HTTP accept headers from the cardholder's browser                                                               |
| `browserColorDepth`   | Bit depth of the color palette from `screen.colorDepth`                                                         |
| `browserJavaEnabled`  | Whether the browser supports Java from `navigator.javaEnabled`                                                  |
| `browserLanguage`     | Browser language from `navigator.language` (IETF BCP47)                                                         |
| `browserScreenHeight` | Screen height in pixels from `screen.height`                                                                    |
| `browserScreenWidth`  | Screen width in pixels from `screen.width`                                                                      |
| `browserTZ`           | Time zone offset in minutes from UTC                                                                            |
| `browserUserAgent`    | HTTP user-agent header                                                                                          |
| `challengeWindowSize` | Challenge window dimensions: `01` = 250x400, `02` = 390x400, `03` = 500x600, `04` = 600x400, `05` = Full screen |

### Start Authentication Response {#start-authentication-response}

The response `auth.status` determines the next step:

|       Status       |                 Meaning                  |              Next Step              |
|--------------------|------------------------------------------|-------------------------------------|
| `AUTHENTICATED`    | Frictionless authentication succeeded.   | Redirect to the consents info page. |
| `AUTH_IN_PROGRESS` | A 3DS challenge is required.             | Display the challenge iframe.       |
| `AUTH_FAILED`      | Authentication failed at the ACS/issuer. | Display an error page.              |

When the status is `AUTH_IN_PROGRESS`, the response includes challenge parameters:

|   Parameter   |          Description          |
|---------------|-------------------------------|
| `acsUrl`      | URL for the challenge window  |
| `encodedCReq` | Encoded 3DS challenge request |

When authentication fails, the response may include additional error details:

|      Parameter      |                            Description                            |
|---------------------|-------------------------------------------------------------------|
| `cardholderInfo`    | Optional message from the ACS/issuer to display to the cardholder |
| `transStatus`       | Whether the transaction qualifies as an authenticated transaction |
| `transStatusReason` | Reason for the transaction status value                           |

## Step 3: 3DS Challenge {#step-3-3ds-challenge}

If a challenge is required, the reference app renders a challenge page that displays a 3DS challenge iframe.

![3DS challenge iframe displayed in the reference app](https://static.developer.mastercard.com/content/consent-management/img/ref-app-card-consent-threeds.png)

The challenge page calls the `doChallenge` JavaScript function:

```javascript
function doChallenge(acsUrl, encodedCReq) {
    const iframe = document.createElement("iframe");
    iframe.id = "3ds-challenge";
    iframe.width = "600px";
    iframe.height = "400px";
    document.body.appendChild(iframe);

    // POST the challenge request to the ACS URL inside the iframe
    const win = iframe.contentWindow;
    if (win != null) {
        const doc = win.document;
        doc.open();
        doc.write(/* form that POSTs creq to acsUrl */);
        doc.close();
    }

    window.addEventListener("message", challengeCompleteListener);
}
```

The challenge iframe displays the issuer's authentication prompt (for example, an OTP or biometric check). Once the cardholder completes the challenge, the iframe posts a `threeds-challenge-notification` message to the parent window, which redirects to `/verify-authentication`.

The next step is [Verify Authentication](https://developer.mastercard.com/consent-management/documentation/tutorials-and-guides/card-consents-tutorial/verify-auth/index.md).
