<!--
{
  "availability" : [
    "iOS: 14.0.0 -",
    "iPadOS: 14.0.0 -",
    "macCatalyst: 14.0.0 -",
    "macOS: 11.0.0 -",
    "tvOS: 15.0.0 -",
    "visionOS: 1.0.0 -",
    "watchOS: 9.0.0 -"
  ],
  "documentType" : "symbol",
  "framework" : "DeviceCheck",
  "identifier" : "/documentation/DeviceCheck/DCAppAttestService/generateKey(completionHandler:)",
  "metadataVersion" : "0.1.0",
  "role" : "Instance Method",
  "symbol" : {
    "kind" : "Instance Method",
    "modules" : [
      "DeviceCheck"
    ],
    "preciseIdentifier" : "c:objc(cs)DCAppAttestService(im)generateKeyWithCompletionHandler:"
  },
  "title" : "generateKey(completionHandler:)"
}
-->

# generateKey(completionHandler:)

Creates a new cryptographic key for use with the App Attest service.

```
func generateKey(completionHandler: @escaping @Sendable (String?, (any Error)?) -> Void)
```

## Parameters

`completionHandler`

A closure that the method calls upon completion with
the following parameters:

- `keyId`:  An identifier that you use to refer to the key. The framework securely
  stores the key in the Secure Enclave.
- `error`:  A [`DCError`](/documentation/DeviceCheck/DCError-swift.struct) instance that indicates the
  reason for failure, or `nil` on success.

## Discussion> Concurrency Note: You can call this method from synchronous code using a completion handler,
> as shown on this page, or you can call it as an asynchronous method that has the
> following declaration:
> 
> ```swift
> func generateKey() async throws -> String
> ```
> 
> For example:
> 
> ```swift
> let keyIdentifier = try await generateKey()
> ```
> 
> For information about concurrency and asynchronous code in Swift, see <doc://com.apple.documentation/documentation/Swift/calling-objective-c-apis-asynchronously>.

Call this method to request the creation of a secure, unattested key pair on
a device for a specific user. On success, the method provides your app with
an identifier that represents the key pair stored in the Secure Enclave.
Because there’s no way to use or retrieve the key without the identifier,
you’ll want to either record it in your app or on your server right away. If
key generation fails, the closure provides a [`DCError`](/documentation/DeviceCheck/DCError-swift.struct) that
indicates the reason for the failure.

Create a unique key for each user account on a device. Otherwise it’s hard
to detect an attack that uses a single compromised device to serve multiple
remote users running a compromised version of your app. For more
information, see [Assessing fraud risk](/documentation/DeviceCheck/assessing-fraud-risk).

After you get the identifier, you call the
[`attestKey(_:clientDataHash:completionHandler:)`](/documentation/DeviceCheck/DCAppAttestService/attestKey(_:clientDataHash:completionHandler:))
method with the key identifier to ask Apple to attest to the validity of the
associated key. Later, you call the
[`generateAssertion(_:clientDataHash:completionHandler:)`](/documentation/DeviceCheck/DCAppAttestService/generateAssertion(_:clientDataHash:completionHandler:))
method with the key identifier to answer a challenge from your server, and
establish the legitimacy of this instance of your app.

---

Copyright &copy; 2026 Apple Inc. All rights reserved. | [Terms of Use](https://www.apple.com/legal/internet-services/terms/site.html) | [Privacy Policy](https://www.apple.com/privacy/privacy-policy)