# iOS

_Encrypt data client-side, collect card details & perform 3D Secure authentication._

## Supported Platforms

- iOS 15+
- macOS 12+

## Quickstart

### Install SDK

The Evervault iOS SDK can be installed using the Swift Package Manager.

1. Open your Xcode project.
2. Navigate to **File** > **Swift Packages** > **Add Package Dependency**.
3. Enter the repository URL for the Evervault iOS SDK: `https://github.com/evervault/evervault-ios.git`.
4. Choose the latest available version or specify a version rule.
5. Click **Next** and follow the instructions to integrate the package into your project.

#### Initialize SDK

Now, let's initialize the SDK using our App and Team ID. If you don't have one yet, you can get one by creating an App in the [Evervault Dashboard](https://app.evervault.com).

```swift
import EvervaultCore

Evervault.shared.configure(teamId: "<TEAM_ID>", appId: "<APP_ID>")
```

If you need multiple instances of the Evervault SDK you can use the initializer as follows:

```swift
import EvervaultCore

let evervault = Evervault.init(teamId: "<TEAM_ID>", appId: "<APP_ID>")
```

### Encrypting Data

Once the SDK is configured, you can use the `encrypt` method to encrypt your sensitive data. The `encrypt` method accepts various data types, including Boolean, Numerics, Strings, Arrays, Dictionaries, and Data.

Here's an example of encrypting a password:

```swift
let encryptedPassword = Evervault.shared.encrypt("Super Secret Password")
```

Or using a dedicated instance:

```swift
let encryptedPassword = evervault.encrypt("Super Secret Password")
```

The `encrypt` method returns an `Any` type, so you will need to safely cast the result based on the data type you provided. For Boolean, Numerics, and Strings, the encrypted data is returned as a String. For Arrays and Dictionaries, the encrypted data maintains the same structure but is encrypted. For Data, the encrypted data is returned as encrypted Data, which can be useful for encrypting files.

### Decrypting Data

Decrypts data previously encrypted with the `encrypt()` function or through Relay.

The `decrypt()` method allows you to decrypt previously encrypted data using a token.

The token is a time bound token for decrypting data. The token can be generated using our [backend SDKs](/sdks) or through our [REST API](/api).

The payload must be the same payload that was used to create the token and expires in a maximum of 10 minutes depending on the expiry set when creating the token.

```swift
let encryptedPassword = Evervault.shared.encrypt("Super Secret Password")
let decrypted: String = Evervault.shared.decrypt('<token generated by your backend application>', encryptedPassword)
```

### Inputs

The Evervault iOS SDK also includes the `EvervaultInputs` module, which provides a SwiftUI view called `PaymentCardInput`. This view is designed for capturing credit card information and automatically encrypts the credit card number and CVC without exposing the unencrypted data. The `PaymentCardInput` view can be customized to fit your application's design.

To use `PaymentCardInput`, make sure you have imported the `EvervaultInputs` module in your file, and then simply add the view to your SwiftUI hierarchy:

```swift
import EvervaultInputs

struct ContentView: View {

    @State private var cardData = PaymentCardData()

    var body: some View {
        VStack {
            PaymentCardInput(cardData: $cardData)

            // Data captured:
            Text("Encrypted credit card number: \(cardData.card.number)")
        }
    }
}
```

Fields can be optionally displayed by passing in the enabledFields struct. For example if you with to only render the Card Number field use the following code.

```swift
import EvervaultInputs

struct ContentView: View {

    private var enabledFields = EnabledFields(isCardNumberEnabled: true, isExpiryEnabled: false, isCVCEnabled: false)

    @State private var cardData = PaymentCardData()

    var body: some View {
        VStack {
            PaymentCardInput(cardData: $cardData, fields: enabledFields)

            // Data captured:
            Text("Encrypted credit card number: \(cardData.card.number)")
        }
    }
}
```

The encrypted credit card number and CVC are captured in the `PaymentCardData` Binding, as well as the expiry month and year and validation fields.

#### Styling

Internally, the `PaymentCardInput` view uses SwiftUI `TextField`s. These can be customized using SwiftUI modifiers like any other `TextField`s in your application:

```swift
    PaymentCardInput(cardData: $cardData)
        .font(.footnote)
        .foregroundColor(.blue)
```

To provide more customization options, the `PaymentCardInput` can be styled using a `PaymentCardInputStyle`. There are two build-in styles:

- `InlinePaymentCardInputView` (the default style) - puts the credit card number, expiry and cvc fields all on a single row.

![Screenshot of the iOS PaymentCardInput with Inline styling]()

To explicitly use this style:

```swift
    PaymentCardInput(cardData: $cardData)
        .paymentCardInputStyle(.inline)
```

- `RowsPaymentCardInputStyle` - puts the credit card number on a single row. Below it, places the expiry and cvc fields next to each other.

![Screenshot of the iOS PaymentCardInput with Rows styling]()

To use this style:

```swift
    PaymentCardInput(cardData: $cardData)
        .paymentCardInputStyle(.rows)
```

If these two styles do not match your use case, you can create your own style:

```swift
struct CustomPaymentCardInputStyle: PaymentCardInputStyle {

    func makeBody(configuration: Configuration) -> some View {
        VStack(alignment: .center) {
            configuration.cardImage

            Text("CC Number").font(.title3)
            configuration.cardNumberField

            Divider()

            Text("Expiry").font(.title3)
            configuration.expiryField

            Divider()

            Text("CVC").font(.title3)
            configuration.cvcField
        }
    }
}
```

```swift
    PaymentCardInput(cardData: $cardData)
        .paymentCardInputStyle(CustomPaymentCardInputStyle())
```

### Attest Enclaves

The Evervault iOS SDK includes the ability to attest connections to [Enclaves](/enclaves).

To [attest your Enclave](/enclaves#attestation-in-tls), you need to provide the expected PCRs to an Enclave session.

```swift
import EvervaultCore
import EvervaultEnclaves

//Note: Make sure app uuid is hyphenated (eg: app-123456).
let url = URL(string: "https://<ENCLAVE_NAME>.<APP_UUID>.enclave.evervault.com")
let enclaveSession = Evervault.enclaveSession(
  enclaveAttestationData: EnclaveAttestationData(
    enclaveName: "<ENCLAVE_NAME>",
    appUuid: "<APP_UUID>",
    pcrs: PCRs(
      pcr0: "<PCR0>",
      pcr1: "<PCR1>",
      pcr2: "<PCR2>",
      pcr8: "<PCR8>",
    )
  )
)

do {
  let response = try await enclaveSession.data(from: url)
  // ...
} catch {
  // ...
}
```

### Apple Pay®

> **Beta**
>
> Evervault Apple Pay for iOS is currently in Beta. Please contact
>   support@evervault.com for more information.

The Evervault iOS SDK provides support for Apple Pay on iOS, enabling secure handling of card data during mobile transaction flows. When a customer taps the Apple Pay button in your app, our SDK will give you the Apple Pay card token (DPAN) from the user's device.

Instead of using Apple's default encryption, the SDK extracts the customer's card details, including the card token and "cryptogram", and returns them in an Evervault-encrypted payload. This allows you to securely access sensitive values while ensuring they remain protected through Evervault's encryption infrastructure.

The encrypted payload can then be safely passed to any downstream system or payment processor for transaction authorization using our proxy, Evervault [Relay](/relay).

In [Sandbox apps](/developers/sandbox), the encrypted network token maps to a [brand-specific test card](/cards/apple-pay#testing-sandbox) based on the card the customer selects in their Apple Wallet.

#### Prerequisites

- You must have an individual or organisational Apple Developer account.

- All users of Apple Pay agree to adhere to the [Apple Pay Terms and Conditions](https://www.apple.com/legal/internet-services/apple-pay-wallet/us/).

#### Register for an Apple Merchant ID

Before you can use Apple Pay for iOS with Evervault you need to obtain an Apple Merchant ID by [registering for a new identifier](https://developer.apple.com/help/account/capabilities/configure-apple-pay#create-a-merchant-identifier) on the Apple Developer portal.
Fill out the description and identifier. We recommend you use the name of your app as the identifier e.g. `merchant.com.<YOUR_APPS_NAME>`

#### Create a new Apple Pay Payment Processing Certificate

Apple Pay needs to encrypt payment data such as card details. You will need a payment processing certificate for your app to allow Apple Pay to encrypt those details within your app.

In the Evervault dashboard, click the `Payments` tab at the top of the page. Then, on the left-hand side of the page click `Apple Pay` and at the bottom of the page under `Certificates`, click `Add certificate`. Follow the on screen instructions.

As part of this flow, Evervault will provide you with a certificate signing request that you must download.

Then, in a new tab, in the Apple Developer portal, under [Certificates](https://developer.apple.com/account/resources/certificates/add), create an `Apple Pay Payment Processing Certificate`, select the Merchant ID that you created in the previous step and click `Continue`. Under the `Apple Pay Payment Processing Certificate` section, click `Create Certificate` and upload the certificate signing request you downloaded from the Evervault dashboard.

Download the Apple certificate you just created and go back to the Evervault dashboard and in the certificate set up dialog, upload the certificate you just downloaded from Apple.

#### Setting up Xcode

Once you have created your merchant identifier and payment processing certificate, you need to add the Apple Pay capability to your app in Xcode.

Open your project settings, click the `Signing & Capabilities` tab, and add the Apple Pay capability. You might be prompted to sign in to your developer account. Select the merchant ID you created earlier, and now your app is ready to accept Apple Pay.

#### Create a Transaction

Next you will need to create a transaction to describe the payment you want to process. You will need to provide the country, currency, and line items for the transaction. The last item is the total for the transaction.

If the transaction is not constructed correctly e.g country or currency fields aren't correct or there are no summary items then an `EvervaultError.InvalidTransaction` error will be thrown.

Please refer to [Apple's documentation](https://developer.apple.com/documentation/passkit/pkpaymentrequest/#Setting-currency-and-region-information) on requirements for country and currency and `amount` fields.

```swift
import EvervaultPayment

let oneOff = try! OneOffPaymentTransaction(
  country: "IE",
  currency: "EUR",
  paymentSummaryItems: [
    SummaryItem(label: "Mens Shirt", amount: Amount("30.00")),
    SummaryItem(label: "Socks", amount: Amount("5.00")),
    SummaryItem(label: "Total", amount: Amount("35.00"))
  ]
)

let transaction = EvervaultPayment.Transaction.oneOffPayment(oneOff)
```

`OneOffPaymentTransaction` and `RecurringPaymentTransaction` also accept a `requestPayerDetails` parameter to request billing contact fields — such as the payer's name, email, phone, or postal address — using PassKit's own `PKContactField` values:

```swift
import EvervaultPayment

let oneOff = try! OneOffPaymentTransaction(
  country: "IE",
  currency: "EUR",
  paymentSummaryItems: [
    SummaryItem(label: "Mens Shirt", amount: Amount("30.00")),
    SummaryItem(label: "Socks", amount: Amount("5.00")),
    SummaryItem(label: "Total", amount: Amount("35.00"))
  ],
  requestPayerDetails: [.name, .phoneticName, .phoneNumber, .emailAddress, .postalAddress]
)

let transaction = EvervaultPayment.Transaction.oneOffPayment(oneOff)
```

#### Check if Apple Pay is supported

Before displaying Apple Pay as a payment option, use the `availability(supportedNetworks:)` method to check whether the device supports Apple Pay, and whether the customer has a card in their wallet. It returns one of three states, matching the [web SDK](#availability):

- `available`: Apple Pay is supported and the customer has a usable card.
- `unavailable`: Apple Pay is supported, but the customer hasn't added a card for the networks you accept.
- `unsupported`: Apple Pay isn't supported on this device.

```swift
let availability = EvervaultPaymentViewRepresentable.availability(supportedNetworks: [.visa, .masterCard, .amex])
```

Use `unsupported` to hide the Apple Pay button entirely. Use `unavailable` to show a **Set Up Apple Pay** button instead of a regular buy button (see [Customise the Apple Pay button](#customise-the-apple-pay-button) for more details).

> **Deprecated**
>
> `isAvailable()` only reports whether the device is capable of Apple Pay. It
>   doesn't tell you whether the customer has a card set up. Because of that, it
>   can't distinguish between "no card added" and "card not supported." Use
>   `availability(supportedNetworks:)` instead.

```swift
let isAvailable = EvervaultPaymentViewRepresentable.isAvailable()
```

#### Render the Apple Pay button

Next you can render the Apple Pay button. When you do this, you will need to pass in your Evervault App ID, your Apple Merchant Identifier, the transaction object, the card networks you support, and a callback closure:

- `authorizedResponse`: Whenever the user successfully authorizes the payment, the decrypted `ApplePayResponse` (containing token, card info, cryptogram, etc.) will be written into your `@State` variable. You can react to that state change however you like — navigate onward, show a confirmation screen, or send it off to your own backend to be sent via an Evervault Relay to your PSP. Refer to [this section](/sdks/ios#processing-the-payment) for the structure of the response.
- `onResult`: Use this callback to reset UI state or advance your checkout flow after the sheet closes with a definite outcome (either success or failure). Failures can happen when Apple Pay is unavailable, the transaction is invalid, presentation fails, or if Evervault can't decrypt the payment details. The callback returns a `Result<Void, EvervaultError>`. The `EvervaultError` includes a `localizedDescription` you can display in an alert, log for diagnostics, or present however appropriate. `onResult` doesn't fire if the customer cancels.
- `onCancel`: Use this modifier to detect when the customer dismisses the sheet without authorizing a payment (e.g., taps **Cancel**). This is distinct from the success or failure provided by `onResult`.

```swift
struct ContentView: View {
  @State private var applePayResponse: ApplePayResponse? = nil
  let transaction = buildTransaction()

  var body: some View {
    VStack(spacing: 20) {
      EvervaultPaymentViewRepresentable(
        appId: "YOUR_EVERVAULT_APP_ID",
        appleMerchantId: "YOUR_APPLE_MERCHANT_IDENTIFIER",
        transaction: transaction,
        supportedNetworks: [.visa, .masterCard, .amex],
        authorizedResponse: $applePayResponse) { result in
            switch result {
            case .success(_):
                print("Payment sheet dismissed with success")
                if (applePayResponse != nil) {
                    // Send to PSP via Relay on your backend
                }
                break
            case let .failure(error):
                print("Payment error: \(error.localizedDescription)")
                break
            }
        }
        .onCancel {
            print("Payment sheet cancelled")
        }
    }
  }
}
```

#### Processing the Payment

If the payment is handled successfully, the Evervault encrypted payment method is available in `$applePayResponse` (in the example above). The `authorizedResponse` is an `ApplePayResponse` object containing the payment method details encrypted with the Evervault public key. You can send this encrypted payment method to your server and use Evervault Relay to decrypt the payment details when you send them to your PSP.

The `ApplePayResponse` object represented as JSON contains the following fields:

```json
{
  "networkToken": {
    "number": "ev:Tk9D:hY5KJanIPOHBoI8S:AsnnjRl0FDe2zEddBAQG/eI2vN+b...:$",
    "expiry": {
      "month": "12",
      "year": "31"
    },
    "tokenServiceProvider": "Apple"
  },
  "card": {
    "brand": "visa",
    "funding": "debit",
    "segment": "consumer",
    "country": "ie",
    "currency": "eur",
    "issuer": "Revolut Bank Uab"
  },
  "cryptogram": "ev:Tk9D:vUVeybXqrA9Ds4rZ...=:$",
  // The ECI value is optional with Apple Pay.
  // Learn more here: https://developer.apple.com/documentation/passkit/payment-token-format-reference#Detailed-payment-data-keys-3D-Secure
  "eci": "5",
  "paymentDataType": "3DSecure",
  "deviceManufacturerIdentifier": "string",
  "transactionType": "oneOff",
  "transactionId": "5ee9e294a2e79032ca7529b2050c2a878187c54a54f07559cff8281fb9b4716c",

  // Only present if you requested the corresponding contact fields on the transaction
  "billingContact": {
    "givenName": "John",
    "familyName": "Doe",
    "phoneticGivenName": null,
    "phoneticFamilyName": null,
    "emailAddress": "john.doe@example.com",
    "phoneNumber": "1234567890",
    "postalAddress": {
      "street": "123 Main St",
      "city": "City",
      "state": "State",
      "postalCode": "12345",
      "country": "Country",
      "isoCountryCode": "XX"
    }
  },
  "shippingContact": {
    "givenName": "John",
    "familyName": "Doe",
    "phoneticGivenName": null,
    "phoneticFamilyName": null,
    "emailAddress": "john.doe@example.com",
    "phoneNumber": "1234567890"
  }
}
```

`transactionType` indicates the transaction category (`oneOff`, `recurring`, or `disbursement`) based on how you created the transaction. `transactionId` is Apple's identifier for the token, and comes from the [PKPaymentToken header](https://developer.apple.com/documentation/passkit/payment-token-format-reference#Header-keys-and-values). Some payment gateways require it to be passed through, though it isn't used to authorize the transaction itself. `billingContact` and `shippingContact` are only populated when the transaction requested those contact fields. `phoneticFamilyName` and `phoneticGivenName` are populated when the customer's Apple Wallet contact card includes a phonetic reading of their name (common in locales like Japan). If there's no phonetic reading, then these two values are `null`.

#### Complete example

Below is a complete example of Evervault Apple Pay in action:

```swift
import SwiftUI
import EvervaultPayment

func buildTransaction() -> EvervaultPayment.Transaction {
  let oneOff = try! OneOffPaymentTransaction(
    country: "IE",
    currency: "EUR",
    paymentSummaryItems: [
      SummaryItem(label: "Mens Shirt", amount: Amount("30.00")),
      SummaryItem(label: "Socks", amount: Amount("5.00")),
      SummaryItem(label: "Total", amount: Amount("35.00"))
    ]
  )
  return Transaction.oneOffPayment(oneOff)
}

struct ContentView: View {
  @State private var applePayResponse: ApplePayResponse? = nil
  let transaction = buildTransaction()
  let supportedNetworks: [Network] = [.visa, .masterCard, .amex]

  var body: some View {
    let availability = EvervaultPaymentViewRepresentable.availability(supportedNetworks: supportedNetworks)

    VStack(spacing: 20) {
      if availability != .unsupported {
        // Apple Pay is supported — show the setup button if there's no card yet
        EvervaultPaymentViewRepresentable(
          appId: "YOUR_EVERVAULT_APP_ID",
          appleMerchantId: "YOUR_APPLE_MERCHANT_IDENTIFIER",
          transaction: transaction,
          supportedNetworks: supportedNetworks,
          buttonStyle: .whiteOutline,
          buttonType: availability == .unavailable ? .setUp : .checkout,
          authorizedResponse: $applePayResponse) { result in
              switch result {
              case .success(_):
                  print("Payment sheet dismissed with success")
                  if (applePayResponse != nil) {
                    // Send to PSP via Relay on your backend
                  }
                  break
              case let .failure(error):
                  print("Payment error: \(error.localizedDescription)")
                  break
              }
          }
          .onCancel {
              print("Payment sheet cancelled")
          }
      } else {
        Text("Not available")
      }
    }
  }
}

#Preview {
    ContentView()
}
```

#### Customise the Apple Pay button

When initialising the `EvervaultPaymentViewRepresentable` you can pass two optional parameters — `buttonType` and `buttonStyle`.

Please refer to the [Apple PassKit documentation](https://developer.apple.com/documentation/passkit/pkpaymentbutton#Configuring-the-appearance) on what preset button styles and types are available.

```swift
EvervaultPaymentViewRepresentable(
  // other fields...
  buttonStyle: .whiteOutline,
  buttonType: .checkout,
)
```

If `availability(supportedNetworks:)` returns `unavailable`, Apple recommends showing the **Set Up Apple Pay** button instead of the default buy button. This takes the customer through the flow for adding a card rather than opening a payment sheet, which would fail.

```swift
EvervaultPaymentViewRepresentable(
  // other fields...
  buttonStyle: .whiteOutline,
  buttonType: availability == .unavailable ? .setUp : .checkout,
)
```

#### Error Handling

All errors from creating the `Transaction` object and the errors surfaced in the `onResult` callback on the `EvervaultPaymentViewRepresentable` can be cast to `EvervaultError`:

- `InvalidTransactionError` - This error is thrown when there is an with the transaction. As a guideline to help prevent encountering this error:
  - `country`: The merchant's two-letter ISO 3166 country code.
  - `currency`: The three-letter ISO 4217 currency code that determines the currency the payment request uses.
  - `amount`: The format of this value depends on the `currency`. It follows ISO 4217 and depends on the minor unit of the currency e.g the number of decimal points for`USD` is 2, so the amount must be formatted as `"50.00"`. This error will be thrown if you try to format the `amount` as `"50.0"`. As another example, `JPY` has no minor unit so the `amount` must be formatted as `"1000"`.
- `ApplePayUnavailableError` - This error is thrown when Apple Pay is not available on the device
- `ApplePayPaymentSheetError` - This error is thrown when an underlying error with the Apple Pay payment sheet occurs.
- `InternalError` - This error is thrown when something goes wrong during the handling of the payment data. An underlying reason will be provided in this case.

### Full example

A complete working example is included in the Evervault iOS package, located in [the EvervaultIOSApp directory](https://github.com/evervault/evervault-ios/tree/main/EvervaultIOSApp).

#### Running the Sample App

To run the sample app:

1. Open the `EvervaultIOSApp.xcodeproj` file in Xcode.
2. Configure your Team ID and App ID in `EvervaultIOSAppApp.swift` or add `EV_TEAM_UUID` and `EV_APP_UUID` Environment Variables the Run Scheme.
3. Select a simulator or physical device as the build target.
4. Build and run the app.

## Reference

### EvervaultCore

#### Evervault.shared.config(teamId: String, appId: String)

A shared instance of the Evervault class. This is the simplest way to get up and running if you only need to use a single Evervault team/app.

```swift
import EvervaultCore

Evervault.shared.configure(teamId: "<TEAM_ID>", appId: "<APP_ID>")
```

**Parameters**

- `teamId` `String` _(required)_ — The Uuid of your Evervault Team
- `appId` `String` _(required)_ — The Uuid of your Evervault App

#### Evervault(teamId: String, appId: String)

Initializes a single instance of the Evervault class. You'll need to use this initializer if you require more than one Evervault team/app.

```swift
import EvervaultCore

let evervault = Evervault(teamId: "<TEAM_ID>", appId: "<APP_ID>")
```

**Parameters**

- `teamId` `String` _(required)_ — The Uuid of your Evervault Team
- `appId` `String` _(required)_ — The Uuid of your Evervault App

#### Evervault.encrypt(\_ data: Any, role: String?) async throws -> Any

Encrypts the provided data using [Evervault Encrypt](/developers/evervault-encryption) and an optional data role.

The encrypt function supports: `Boolean`, Numerics, `String`, `Array`, `Dictionary` and `Data`.

Note: Data Roles aren't yet supported when encrypting data of the `Data` type

```swift
let encryptedData = try await Evervault.shared.encrypt("Super Secret Password")
// or
let encryptedData = try await evervault.encrypt("Super Secret Password")
// or
let encryptedData = try await Evervault.shared.encrypt("Super Secret Password", "data-role")
```

**Parameters**

- `data` `Any` _(required)_ — The data you want to encrypt.

### EvervaultInputs

#### PaymentCardInput(cardData: PaymentCardData)

Create a PaymentCardInput SwiftUI view

```swift
import EvervaultInputs

struct ContentView: View {

    @State private var cardData = PaymentCardData()

    var body: some View {
        VStack {
            PaymentCardInput(cardData: $cardData)

            // Data captured:
            Text("Encrypted credit card number: \(cardData.card.number)")
        }
    }
}
```

**Parameters**

- `cardData` `PaymentCardData` _(required)_ — The card data state for the PaymentCardInput view

### EvervaultEnclaves

#### Evervault.enclaveSession(enclaveAttestationData: AttestationData)

Create a URLSession which will attest connections to your Evervault Enclave.

```swift
import EvervaultCore
import EvervaultEnclaves

let enclaveSession = Evervault.enclaveSession(
  enclaveAttestationData: AttestationData(
    enclaveName: "<ENCLAVE_NAME>",
    pcrs: PCRs(
      pcr0: "<PCR0>",
      pcr1: "<PCR1>",
      pcr2: "<PCR2>",
      pcr8: "<PCR8>",
    )
  )
)
```

**Parameters**

- `enclaveAttestationData` `AttestationData` _(required)_ — The values used during the attestation handshake with your Enclave

#### AttestationData

Config used to compare against the attestation doc served to the client from an Enclave.

**AttestationData**

- `enclaveName` `String` _(required)_ — The name of the Enclave to attest
- `pcrs` `PCRs` _(required)_ — The platform configuration registers to compare against the attestation doc returned from the Enclave

#### PCRs

The attestation measurements measurement expected to be embedded in the attestation document returned from an Enclave.

**PCRs**

- `pcr0` `String` — The value for PCR0 to attest
- `pcr1` `String` — The value for PCR1 to attest
- `pcr2` `String` — The value for PCR2 to attest
- `pcr8` `String` — The value for PCR8 to attest

##### Using the Evervault API as a PCR Provider

The Evervault API exposes an endpoint to retrieve the PCRs for all active versions of your Enclave which you can use to keep your clients in sync with your Enclave across deployments.

```swift
import EvervaultCore
import EvervaultEnclaves

struct AttestedEnclaveView: View {

    private let enclaveName = "my-enclave"
    private let appId = "app_123abc"
    private let enclaveHostname = "my-enclave.app-123abc.enclave.evervault.com"

    public struct EvervaultProviderResponse: Decodable {
        public let data: [PCRs]

        public init(data: [PCRs]) {
            self.data = data
        }
    }

    public var provider: (@escaping ([PCRs]?, Error?) -> Void) -> Void = { completion in
        var request = URLRequest(url: URL(string: "https://api.evervault.com/enclaves/\(enclaveName)/attestation")!)
        request.addValue(appId, forHTTPHeaderField: "x-evervault-app-id")

        URLSession.shared.dataTask(with: request) { data, _, error in
            guard let data = data, error == nil else {
                completion(nil, error ?? NSError(domain: "Evervault Provider", code: -1, userInfo: [NSLocalizedDescriptionKey: "No data or error."]))
                return
            }
            do {
                // Decode the data into a PCRContainer
                let container = try JSONDecoder().decode(EvervaultProviderResponse.self, from: data)
                // Extract the PCRs array from the container and pass it to the completion handler
                completion(container.data, nil)
            } catch {
                print("Error: ", error.localizedDescription)
                completion(nil, error)
            }
        }.resume()
    }

    @State private var responseText: String? = nil

    var body: some View {
        Group {
            if let responseText {
                Text(responseText)
            } else {
                Text("Loading...")
            }
        }
        .padding()
        .task {
            let url = URL(string: "https://\(enclaveHostname)/")!
            let urlSession = Evervault.enclaveAttestationSession(
                enclaveAttestationData: EnclaveAttestationData(
                    enclaveName: enclaveName,
                    appUuid: appId,
                    provider: provider
                )
            )

            do {
                let response = try await urlSession.data(from: url)
                print(response)
            } catch {
                responseText = error.localizedDescription
                print("Error: \(error.localizedDescription)")
            }
        }
    }
}
```

