Skip to content
Mobile
Skill

/device-integrity

Verify device legitimacy and app integrity using DeviceCheck (DCDevice per-device bits) and App Attest (DCAppAttestService key generation, attestation, and assertion flows). Use when implementing fraud prevention, detecting compromised devices, validating app authenticity with

From plugin
swift-ios-skills
1.3k86 skills1 MCP

Claude Code

$ npx -y skills add dpearson2699/swift-ios-skills --skill device-integrity --agent claude-code

SKILL.md

device-integrity.SKILL.md
name: device-integrity
description: "Verify device legitimacy and app integrity using DeviceCheck (DCDevice per-device bits) and App Attest (DCAppAttestService key generation, attestation, and assertion flows). Use when implementing fraud prevention, detecting compromised devices, validating app authenticity with Apple's servers, protecting sensitive API endpoints with attested requests, or adding device verification to a backend architecture."

Device Integrity

Verify that requests to your server come from a genuine Apple device running a legitimate instance of your app. DeviceCheck provides per-device bits for simple flags (e.g., "claimed promo offer"). App Attest uses Secure Enclave keys and Apple attestation to cryptographically prove app legitimacy on sensitive requests.

Contents

  • [DCDevice (DeviceCheck Tokens)](#dcdevice-devicecheck-tokens)
  • [DCAppAttestService (App Attest)](#dcappattestservice-app-attest)
  • [App Attest Key Generation](#app-attest-key-generation)
  • [App Attest Attestation Flow](#app-attest-attestation-flow)
  • [App Attest Assertion Flow](#app-attest-assertion-flow)
  • [Server Verification Guidance](#server-verification-guidance)
  • [Error Handling](#error-handling)
  • [Common Patterns](#common-patterns)
  • [Common Mistakes](#common-mistakes)
  • [Review Checklist](#review-checklist)
  • [References](#references)

DCDevice (DeviceCheck Tokens)

[`DCDevice`](https://sosumi.ai/documentation/devicecheck/dcdevice) generates a unique, ephemeral token that identifies a device. Treat each token as single-use: generate a new token for each server operation instead of caching or reusing one. The token is sent to your server, which then communicates with Apple's servers to read or set two per-device bits. Available on iOS 11+.

Token Generation

import DeviceCheck

func generateDeviceToken() async throws -> Data {
    guard DCDevice.current.isSupported else {
        throw DeviceIntegrityError.deviceCheckUnsupported
    }

    return try await DCDevice.current.generateToken()
}

Sending the Token to Your Server

func sendTokenToServer(_ token: Data) async throws {
    let tokenString = token.base64EncodedString()

    var request = URLRequest(url: serverURL.appending(path: "verify-device"))
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpBody = try JSONEncoder().encode(["device_token": tokenString])

    let (_, response) = try await URLSession.shared.data(for: request)
    guard let httpResponse = response as? HTTPURLResponse,
          httpResponse.statusCode == 200 else {
        throw DeviceIntegrityError.serverVerificationFailed
    }
}

Server-Side Overview

The server exchanges each fresh token with Apple's authenticated DeviceCheck API. Load [DeviceCheck Server Endpoints](references/device-integrity-patterns.md#devicecheck-server-endpoints) for endpoint and environment details.

What the Two Bits Are For

Apple stores two Boolean values per device per developer team. You decide what they mean. Common uses:

  • **Bit 0:** Device has claimed a promotional offer.
  • **Bit 1:** Device has been flagged for fraud.

Bits persist across app reinstall. You control when to reset them via the server API.

DCAppAttestService (App Attest)

[`DCAppAttestService`](https://sosumi.ai/documentation/devicecheck/dcappattestservice) validates that a specific instance of your app on a specific device is legitimate. It uses a hardware-backed key in the Secure Enclave to create cryptographic attestations and assertions. Available on iOS 14+.

The flow has three phases: 1. **Key generation** -- create a key pair in the Secure Enclave. 2. **Attestation** -- Apple certifies the key belongs to a genuine Apple device running your app. 3. **Assertion** -- sign server requests with the attested key to prove ongoing legitimacy.

Checking Support

import DeviceCheck

let attestService = DCAppAttestService.shared

guard attestService.isSupported else {
    // Fall back to DCDevice token or other risk assessment.
    // App Attest is not available on simulators or all device models.
    return
}

For app extensions, App Attest is supported only in Action, extensible SSO, and watchOS extensions. Treat other extension types as unsupported even if `isSupported` returns `true`.

App Attest Key Generation

Generate one cryptographic key pair per user account on each device. The private key stays in the Secure Enclave. The returned `keyId` is the only identifier your app can later use to access the key, so record and reuse the account/device-scoped `keyId`; do not share one key across users. Avoid unnecessary regeneration because each new key affects App Attest key-count risk metrics. Only treat the `keyId` as usable after your server verifies attestation. If server verification fails, discard the `keyId` and generate a new key before retrying.

import DeviceCheck

actor AppAttestManager {
    private let service = DCAppAttestService.shared
    private var keyId: String?

    /// Generate and record a key pair for App Attest.
    func generateKeyIfNeeded() async throws -> String {
        if let existingKeyId = loadKeyIdFromKeychain() {
            self.keyId = existingKeyId
            return existingKeyId
        }

        let newKeyId = try await service.generateKey()
        saveKeyIdToKeychain(newKeyId)
        self.keyId = newKeyId
        return newKeyId
    }

    // MARK: - Keychain helpers (simplified)

    private func saveKeyIdToKeychain(_ keyId: String) {
        let data = Data(keyId.utf8)
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: "app-attest-key-id-\(currentAccountID)",
            kSecAttrService as String: Bundle.main.bundleIdentifier ?? "",
            kSecValueData as String: data,
            kSecAttrAccessible as String: kSecAttrAccessib
Read more
@dpearson2699
Ships withswift-ios-skills

86 agent skills optimized for iOS 26+ development with Swift 6.3 and modern Apple frameworks.

1.3k86 skills1 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
1.3k
Star history of dpearson2699/swift-ios-skills on GitHub, a chart by star-history.com

Other skills on swift-ios-skills.

alarmkit

alarmkit

Implement AlarmKit alarms and countdown timers for iOS and iPadOS with Lock Screen, Dynamic Island, StandBy, and paired Apple…

app-clips

app-clips

Build iOS App Clips with invocation URLs, App Clip Codes, NFC, QR codes, Safari banners, Maps, Messages, target setup, App Store…

More skills from other plugins.

deep-code-review

deep-code-review

In-depth design-focused code review - understands codebase context before evaluating PR changes, posts structured feedback to…

expo1d53k
@expo@expoInstall Skill
modlens

modlens

Plug-in vision for text-only models. Hard rule: when a file path or URL with an image extension (.png, .jpg, .jpeg, .webp, .gif,…

modlens2w4.6k
@liustack@liustackInstall Skill
appllama-app-design-skill

appllama-app-design-sk…

Build native-feeling, benchmark-quality mobile app screens (Expo / React Native). Use when designing or implementing any mobile…

appllama2mo3.9k
@appllama@appllamaInstall Skill

Questions about device-integrity.

Which coding agents can use device-integrity?
device-integrity installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.