diff --git a/docs/api-reference.md b/docs/api-reference.md
new file mode 100644
index 00000000..cc122efd
--- /dev/null
+++ b/docs/api-reference.md
@@ -0,0 +1,49 @@
+# API Reference
+
+This section provides a high-level overview of the main classes and protocols within `AppCheckCore`. For detailed API documentation, please refer to the header files directly.
+
+## Core Classes
+
+### `GACAppCheck`
+The central class for managing App Check tokens. It serves as the primary entry point for your application to interact with the App Check system.
+
+* **Purpose:** Manages the lifecycle of App Check tokens, including fetching, caching, and refreshing. It delegates attestation logic to an `GACAppCheckProvider` instance.
+* **Key Methods:**
+ * `tokenForcingRefresh:completion:`: Requests an App Check token, with an option to force a refresh, bypassing the cache.
+ * `limitedUseTokenWithCompletion:`: Requests a limited-use App Check token, which does not affect the primary token's refresh cycle.
+
+### `GACAppCheckSettings`
+Provides configurable settings for the `AppCheckCore` library.
+
+* **Purpose:** Allows customization of various behaviors, such as token refresh intervals or logging levels.
+
+### `GACAppCheckToken`
+Represents an App Check token received from the App Check backend.
+
+* **Properties:**
+ * `token` (`NSString *`): The actual App Check token string.
+ * `expirationDate` (`NSDate *`): The date and time when the token expires.
+
+### `GACAppCheckTokenResult`
+A wrapper object containing either an `GACAppCheckToken` upon success or an `NSError` upon failure.
+
+* **Properties:**
+ * `token` (`GACAppCheckToken * _Nullable`): The App Check token if the request was successful.
+ * `error` (`NSError * _Nullable`): An error object if the token request failed.
+
+## Protocols
+
+### `GACAppCheckProvider`
+A protocol that defines the interface for App Check providers. Custom providers must conform to this protocol.
+
+* **Purpose:** Abstracts the specifics of how App Check tokens are obtained. Implementations interact with platform-specific attestation services or provide mock tokens.
+* **Key Methods:**
+ * `getTokenWithCompletion:`: Asynchronously fetches a new App Check token.
+ * `getLimitedUseTokenWithCompletion:`: Asynchronously fetches a new limited-use App Check token.
+
+### `GACAppCheckTokenDelegate`
+A protocol for delegates that wish to receive notifications about App Check token updates.
+
+* **Purpose:** Allows your application to react to changes in the App Check token, such as when a new token is fetched or an existing one is refreshed.
+* **Key Methods:**
+ * `appCheck:didChangeToken:`: Notifies the delegate when the App Check token changes.
diff --git a/docs/architecture.md b/docs/architecture.md
new file mode 100644
index 00000000..88458a96
--- /dev/null
+++ b/docs/architecture.md
@@ -0,0 +1,97 @@
+# Architecture & Design
+
+This document details the internal architecture of `AppCheckCore`,
+focusing on token storage, lifecycle management, and security
+mechanisms.
+
+> [!WARNING]
+> This document describes internal implementation details that are subject
+> to change. Rely only on the public API surface for integration
+> (see [App Check Core Documentation](index.md#important-disclaimer)).
+
+## Token Storage
+App Check tokens are sensitive credentials that grant access to your
+backend resources. `AppCheckCore` treats them with high security.
+
+### Keychain Storage
+The `GACAppCheckStorage` class is responsible for persisting App Check
+tokens.
+* **Mechanism:** It uses the iOS Keychain via `GULKeychainStorage`.
+* **Service Name:** `com.google.app_check_core.token_storage`.
+* **Data Protection:** Tokens are stored as `GACAppCheckStoredToken`
+ objects (conforming to `NSSecureCoding`).
+* **Access Groups:** Supports sharing tokens across apps/extensions
+ via Keychain Access Groups (configurable during initialization).
+
+### Artifact Storage (App Attest)
+For the App Attest provider, intermediate artifacts are also stored to
+maintain a stable device identity.
+* **Class:** `GACAppAttestArtifactStorage`
+* **Storage:** Keychain.
+* **Key Suffix:** Keys are namespaced by the service name and resource
+ name (e.g., `my-sdk.projects/123/apps/abc`) to prevent collisions.
+
+## Token Lifecycle Management
+The `GACAppCheck` class acts as the central coordinator.
+
+1. **Request:** The app requests a token via
+ `token(forcingRefresh:completion:)`.
+2. **Cache Check:**
+ * If `forcingRefresh` is `NO`: Checks `GACAppCheckStorage` for a
+ valid, non-expired token.
+ * **Buffer Time:** Tokens are considered "expired" slightly before
+ their actual expiration time to account for clock skew and
+ network latency.
+3. **Fetch (if needed):**
+ * If the cache is empty or expired, or `forcingRefresh` is `YES`,
+ a request is made to the configured `GACAppCheckProvider`.
+4. **Storage:**
+ * Upon successful retrieval, the new token is written to
+ `GACAppCheckStorage`.
+ * Any old token is overwritten.
+5. **Completion:** The token (cached or new) is returned to the caller.
+
+## Exponential Backoff Strategy
+To prevent overwhelming the backend or Apple's servers during failures,
+`AppCheckCore` implements a robust exponential backoff strategy via
+`GACAppCheckBackoffWrapper`.
+
+### Algorithm
+The backoff interval is calculated as follows:
+```math
+Interval = \min(Base \times Jitter, MaxInterval)
+```
+* **Base:** $`2^{retryCount}`$ seconds.
+* **Jitter:** A random multiplier between $1.0$ and $1.5$ (to prevent
+ thundering herd problems).
+* **MaxInterval:** 4 hours.
+
+### Error Policies
+The backoff behavior depends on the error type, specifically HTTP status
+codes returned by the backend:
+
+| HTTP Status Code | Backoff Type | Reason |
+| :--- | :--- | :--- |
+| **< 400** | **None** | Network errors or successful requests do not trigger backoff. |
+| **400 (Bad Request)**
**404 (Not Found)** | **1 Day** | Indicates a project misconfiguration or outdated app version. Unlikely to resolve quickly. |
+| **403 (Forbidden)**
**429 (Too Many Requests)**
**503 (Service Unavailable)** | **Exponential** | Indicates soft deletion, rate limiting, or server overload. Retrying later is appropriate. |
+| **Other 5xx** | **Exponential** | Standard server errors. |
+
+### Implementation
+* **Class:** `GACAppCheckBackoffWrapper`
+* **Usage:** Providers (`GACAppAttestProvider`, `GACDeviceCheckProvider`)
+ wrap their network and attestation calls in this backoff mechanism.
+* **State:** The wrapper tracks the failure count and the last failure
+ time. It resets to 0 upon a successful token fetch.
+
+## Threading Model
+* **Concurrency:** `AppCheckCore` is designed to be thread-safe.
+* **Queues:**
+ * **Main Queue:** Completion handlers are typically dispatched to
+ the main queue.
+ * **Internal Queues:** Providers use private serial queues (e.g.,
+ `com.google.GACAppAttestProvider`) to manage state and
+ sequentialize complex attestation flows (like generating a key,
+ then attesting, then exchanging).
+ * **Background:** Network requests are performed on background
+ queues (`QOS_CLASS_DEFAULT` or `QOS_CLASS_UTILITY`).
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 00000000..74710e96
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,85 @@
+# App Check Core - Documentation
+
+## Introduction
+`AppCheckCore` is the underlying engine for app attestation and token
+management, primarily used by the Firebase iOS SDK but designed for
+broader internal Google use. It provides a robust and secure way to
+verify the authenticity of app instances accessing your backend
+resources. This library supports applications running on iOS, macOS,
+tvOS, and watchOS.
+
+## Key Features
+* **Token Management:** Handles the lifecycle of App Check tokens,
+ including caching and automatic refreshing to ensure continuous
+ protection.
+* **Provider Abstraction:** Abstracts different attestation providers,
+ allowing for flexible integration with various platform-specific
+ integrity mechanisms.
+* **Limited-Use Tokens:** Supports the generation and management of
+ limited-use tokens for scenarios requiring single-use or short-lived
+ authentication.
+
+> [!IMPORTANT]
+> **The detailed architectural and implementation documentation within this
+> `docs/` directory, especially the deep dives into provider internals and
+> decision logic, are provided for comprehensive understanding only.**
+>
+> **Consumers of the App Check Core library should exclusively rely on the
+> public API surface (as defined by the public header files, e.g., in
+> `AppCheckCore/Sources/Public`) for integration. Internal implementation
+> details, including specific error handling flows, storage mechanisms, and
+> concurrency management described herein, are subject to change without
+> notice across library versions.**
+
+## Documentation Sections
+
+* [Usage Guide](usage.md): How to initialize and fetch tokens.
+* [Providers Deep Dive](providers.md): Detailed architectural
+ breakdown of App Attest, DeviceCheck, and Debug providers,
+ including sequence diagrams.
+* [Architecture](architecture.md): Internal design details regarding
+ token storage, caching strategies, and threading.
+* [API Reference](api-reference.md): High-level class overview.
+
+## High-Level Architecture
+This diagram illustrates the core relationships. For detailed sequence
+flows, see [Providers Deep Dive](providers.md).
+
+```mermaid
+classDiagram
+ class GACAppCheck {
+ +tokenForcingRefresh:completion:
+ +limitedUseTokenWithCompletion:
+ }
+
+ class GACAppCheckProvider {
+ <>
+ +getTokenWithCompletion:
+ +getLimitedUseTokenWithCompletion:
+ }
+
+ class GACAppAttestProvider {
+ -AppAttestService
+ -KeyStorage
+ -ArtifactStorage
+ }
+
+ class GACDeviceCheckProvider {
+ -DCDevice
+ }
+
+ class GACAppCheckDebugProvider {
+ -LocalDebugToken
+ }
+
+ class GACAppCheckToken {
+ +token: String
+ +expirationDate: Date
+ }
+
+ GACAppCheck "1" *-- "1" GACAppCheckProvider : uses
+ GACAppCheckProvider <|-- GACAppAttestProvider : implements
+ GACAppCheckProvider <|-- GACDeviceCheckProvider : implements
+ GACAppCheckProvider <|-- GACAppCheckDebugProvider : implements
+ GACAppCheck --> GACAppCheckToken : returns
+```
\ No newline at end of file
diff --git a/docs/providers.md b/docs/providers.md
new file mode 100644
index 00000000..c5b38d5a
--- /dev/null
+++ b/docs/providers.md
@@ -0,0 +1,15 @@
+# App Check Providers: Deep Dive
+
+This section details the internal design and detailed flows of each
+App Check provider, including error handling, retries, and state
+resets.
+
+Select a provider below for detailed documentation:
+
+* [AppAttest Provider](providers/app-attest.md)
+ * The primary provider for modern iOS devices, wrapping `DCAppAttestService`.
+ * Features complex state management, automatic retries, and request coalescing.
+* [DeviceCheck Provider](providers/device-check.md)
+ * A fallback provider for older devices using `DCDevice`.
+* [Debug Provider](providers/debug.md)
+ * For local development and CI/CD environments.
diff --git a/docs/providers/app-attest.md b/docs/providers/app-attest.md
new file mode 100644
index 00000000..be9f5095
--- /dev/null
+++ b/docs/providers/app-attest.md
@@ -0,0 +1,312 @@
+# AppAttest Provider (`GACAppAttestProvider`)
+
+The most complex provider, interacting with `DCAppAttestService`. It
+maintains a stable key pair on the device to sign assertions.
+
+## Overview
+The App Attest provider uses a two-phase process:
+
+1. **Initial Handshake (Attestation):** The SDK generates a cryptographic key
+ pair containing a random challenge and a Key ID. The random challenge is
+ provided by a Firebase backend. The Key ID is provided by an Apple backend,
+ via Apple's `DCAppAttestService` (from the DeviceCheck framework). The
+ key pair is then attested by an Apple backend, via `DCAppAttestService`,
+ which provides an attestation result. This attestation, Key ID, and
+ challenge are sent to a Firebase backend for verification and exchange
+ for an **App Check Token** and an **Attestation Artifact**, which is
+ used to validate token refreshes (assertions).
+2. **Token Refresh (Assertion):** For subsequent requests, the app
+ uses the stored Key ID to sign a challenge (Assertion) from Apple.
+ The Firebase backend verifies this signature against the stored
+ Artifact to issue a new token.
+
+**Stored Artifacts:**
+* **Key ID:** Identifies the key pair on the device (persisted in
+ UserDefaults).
+* **Artifact:** An opaque object from the Firebase backend linking
+ the device's key to the user's session (persisted in Keychain).
+
+## Components
+* **Service:** `DCAppAttestService` (Apple's API).
+* **Storage:**
+ * `GACAppAttestKeyIDStorage`: Stores the generated App Attest Key
+ ID.
+ * **Location:** `UserDefaults` (Suite: `com.firebase.GACAppAttestKeyIDStorage`).
+ * `GACAppAttestArtifactStorage`: Stores the "artifact" returned by
+ the Firebase backend after a successful initial handshake. This
+ artifact effectively links the on-device key to the backend
+ session.
+ * **Location:** Keychain (Service: `com.firebase.app_check.app_attest_artifact_storage`).
+* **Resiliency:**
+ * **Automatic Retry (Internal):** The provider includes an internal
+ retry loop (max 1 attempt) with a 0-second delay. This loop is
+ specifically triggered if an error wrapped as
+ `GACAppAttestRejectionError` occurs.
+ * **Triggers for Reset & Internal Retry:**
+ * `DCErrorInvalidKey` / `DCErrorInvalidInput` (Apple DeviceCheck error).
+ * HTTP 403 (Attestation Rejected) from the backend during handshake.
+ * **Backoff Strategy (External):** An outer `GACAppCheckBackoffWrapper`
+ protects the backend from traffic spikes by enforcing delays on
+ subsequent attempts based on the error type.
+ * **No Backoff (Immediately Permitted):** For non-HTTP errors (e.g.,
+ Apple's `DCError` like `serverUnavailable`), network connectivity
+ issues, storage failures, or parsing errors, the backoff wrapper
+ **does not** enforce a delay. Subsequent `getToken` calls by the
+ app are immediately permitted.
+ * **Exponential Backoff:** Applied to retryable server errors.
+ * HTTP 403 (Project/App Deleted) *if internal retry fails*.
+ * HTTP 429 (Too Many Requests).
+ * HTTP 503 (Server Overloaded).
+ * Other HTTP 5xx (Server Errors) or 4xx not listed above or
+ handled by 1 day backoff.
+ * **1 Day Backoff:** Applied to configuration errors unlikely to
+ resolve quickly.
+ * HTTP 400 (Bad Request).
+ * HTTP 404 (Not Found).
+ * **Other Non-Resetting Errors (State Preserved):** For errors that
+ do not trigger the internal retry loop or an explicit external
+ backoff (e.g., `DCErrorServerUnavailable`, generic network issues,
+ storage errors), the request fails, but the App Attest key and
+ artifact are **preserved**. This allows the app to retry the
+ request later using the same key, aligning with Apple's
+ recommendation to preserve the device's risk metric.
+
+## Attestation State Calculation
+The provider determines its current state by checking for the presence of
+a supported environment, a stored key ID, and a stored artifact. This state
+dictates whether to perform an initial handshake or a token refresh.
+
+```mermaid
+flowchart LR
+ Start([Calculate State]) --> CheckSupport{Is App Attest
Supported?}
+
+ CheckSupport -- Yes --> CheckKey{Stored Key ID?}
+
+ CheckSupport -- No --> Unsupported["State: Unsupported"]
+
+ CheckKey -- Yes --> CheckArtifact{Stored Artifact
for Key ID?}
+
+ CheckKey -- No --> SupportedInitial["State: SupportedInitial
(Ready for Handshake)"]
+
+ CheckArtifact -- Yes --> KeyRegistered["State: KeyRegistered
(Key & Artifact exist)"]
+
+ CheckArtifact -- No --> KeyGenerated["State: KeyGenerated
(Key exists, no Artifact)"]
+```
+
+## Decision Logic & State Machine
+Before executing a handshake, the provider determines the correct flow
+based on the internal state and manages concurrent requests.
+
+> [!IMPORTANT]
+> **Note on Limited Use:** Limited-use tokens are never reused/coalesced.
+> If a limited-use token is requested (or if one is currently being
+> fetched), the new request will "chain" (wait for the ongoing one to
+> finish) and then start a fresh handshake to ensure a unique token is
+> generated.
+
+```mermaid
+flowchart LR
+ Start[getToken] --> Ongoing{Ongoing Op?}
+
+ Ongoing -- No --> StartNew[Start New Request]
+ Ongoing -- Yes --> Conflict{Limited Request
or Mismatch?}
+
+ Conflict -- Yes --> Queue[Queue New Request]
+ Conflict -- No --> Reuse[Reuse Existing Request]
+
+ Queue --> Backoff
+ StartNew --> Backoff
+
+ subgraph Execution ["Backoff Wrapped Execution"]
+ direction LR
+ Backoff[Check Backoff]
+ StateCheck["Attestation State?
(See 'Attestation State Calculation' above)"]
+
+ Backoff --> StateCheck
+
+ StateCheck -->|Yes| KeyCheck{Key ID?}
+
+ KeyCheck -- No --> Flow1[Flow 1: Initial]
+ KeyCheck -- Yes --> ArtifactCheck{Artifact?}
+
+ ArtifactCheck -- No --> Flow1
+ ArtifactCheck -- Yes --> Flow2[Flow 2: Refresh]
+
+ StateCheck -->|No| Error[Error]
+ end
+
+ Reuse -.- Footnote["Note: The 'ongoingGetTokenOperation' tracks the active fetch.
Standard requests reuse it (unless the active fetch is Limited-use).
Limited-use requests always queue a new, sequential fetch."]
+ Queue -.- Footnote
+ StartNew -.- Footnote
+```
+
+## Concurrent Request Handling
+The `GACAppAttestProvider` carefully manages concurrent calls to
+`getToken(limitedUse:)` to ensure correctness and efficiency:
+
+* **No Ongoing Operation:** If no token fetching operation is in
+ progress, a new one is started, and its promise is stored as the
+ `ongoingGetTokenOperation`.
+* **Reuse (Standard Tokens Only):** If a standard (non-limited use)
+ token is requested, and there's an `ongoingGetTokenOperation` that
+ is also for a standard token, the existing promise is reused. This
+ ensures only one actual token fetch occurs for multiple concurrent
+ standard requests.
+* **Chaining (Limited-Use or Mismatched Requests):**
+ * If a limited-use token is requested, *or*
+ * If a standard token is requested but the `ongoingGetTokenOperation`
+ is for a limited-use token (or vice versa),
+ the new request will **chain**. This means it waits for the currently
+ `ongoingGetTokenOperation` to complete, and then initiates a *new*, separate
+ token fetching sequence. This prevents limited-use tokens from being
+ accidentally reused and ensures distinct token types are handled
+ independently.
+
+```mermaid
+sequenceDiagram
+ participant AppA as App (Standard)
+ participant AppB as App (Limited)
+ participant AppC as App (Standard)
+ participant Provider as GACAppAttestProvider
+
+ AppA->>Provider: getToken(false)
+ activate Provider
+ Note right of Provider: No ongoing op.
Start new op (standard).
Set ongoingGetTokenOperation.
+ Provider-->>Provider: Start Flow 1/2 sequence
+
+ AppB->>Provider: getToken(true)
+ activate Provider
+ Note right of Provider: Ongoing op (standard) exists.
New request is limited-use.
Chain: Wait for ongoing, then start new op.
+ Provider->>Provider: Await ongoing op completion
+ deactivate Provider
+
+ AppC->>Provider: getToken(false)
+ activate Provider
+ Note right of Provider: Ongoing op (standard) exists.
New request is standard.
Reuse ongoing op's promise.
+ Provider-->>AppC: App Check Token (from ongoing op)
+ deactivate Provider
+
+ Provider-->>AppA: App Check Token (from completed op)
+ deactivate Provider
+
+ Provider-->>Provider: Start new Flow 1/2 for App (Limited)
+ activate Provider
+ Provider-->>AppB: App Check Token (from new op)
+ deactivate Provider
+```
+
+## Flow 1: Initial Handshake (Attestation)
+Occurs when the app runs for the first time, or if the stored artifact
+
+| Component | Details |
+| :--- | :--- |
+| **Inputs** | `limitedUse` (Bool)
Optional existing `Key ID` |
+| **Outputs** | `App Check Token` (Returned)
`Key ID` (Persisted)
`Artifact` (Persisted) |
+
+> [!NOTE]
+> **Note on Error Handling:** Errors not explicitly handled in this flow
+> (e.g., network issues, storage failures) will result in the promise being
+> rejected. Such errors may be subject to external backoff if applicable,
+> and all errors eventually bubble up to the caller (unless successfully
+> resolved by an internal retry).
+
+```mermaid
+sequenceDiagram
+ participant App
+ participant Provider as GACAppAttestProvider
+ participant Apple as DCAppAttestService
(Apple's DeviceCheck Framework)
+ participant AppleServer as Apple Server
+ participant API as GACAppAttestAPIService
+ participant Backend as Firebase Backend
+
+ App->>Provider: getToken(limitedUse)
+
+ loop Retry Loop (Max 1 Retry for GACAppAttestRejectionError)
+ par Parallel Execution
+ Provider->>API: getRandomChallenge()
+ API->>Backend: POST /generateAppAttestChallenge
+ Backend-->>API: { "challenge": "..." }
+ API-->>Provider: Challenge
+ and
+ Provider->>Apple: generateKey() (If needed)
+ Apple-->>Provider: Key ID
+ end
+
+ Provider->>Apple: attestKey(keyId, clientDataHash=SHA256(challenge))
+ Apple->>AppleServer: Contact App Attest Service
+ AppleServer-->>Apple: Attestation Result
+
+ alt Attestation Failed (Invalid Key/Input)
+ Apple-->>Provider: DCErrorInvalidKey / Input
+ Provider->>Provider: RESET: Delete KeyID & Artifact
+ Note right of Provider: Throws GACAppAttestRejectionError,
Triggering Loop Retry
+ else Attestation Success
+ Apple-->>Provider: Attestation Object
+ Provider->>API: attestKeyWithAttestation(attestation, keyID, challenge, limitedUse)
+ API->>Backend: POST /exchangeAppAttestAttestation
{ limited_use: true/false }
+
+ alt Backend Rejection (403)
+ Backend-->>API: 403 Forbidden
+ API-->>Provider: Error (403)
+ Provider->>Provider: RESET: Delete KeyID & Artifact
+ Note right of Provider: Throws GACAppAttestRejectionError,
Triggering Loop Retry
+ else Success
+ Backend-->>API: { "token": "...", "artifact": "..." }
+ API-->>Provider: { "token": "...", "artifact": "..." }
+ Provider->>Provider: Store Artifact & Key ID
+ Provider-->>App: App Check Token
+ end
+ end
+ end
+```
+
+## Flow 2: Token Refresh (Assertion)
+Occurs for subsequent requests using the established key pair.
+
+| Component | Details |
+| :--- | :--- |
+| **Inputs** | `limitedUse` (Bool)
`Key ID` (From Storage)
`Artifact` (From Storage) |
+| **Outputs** | `App Check Token` (Returned) |
+
+> [!NOTE]
+> **Note on Error Handling:** Errors not explicitly handled in this flow
+> (e.g., network issues, storage failures) will result in the promise being
+> rejected. Such errors may be subject to external backoff if applicable,
+> and all errors eventually bubble up to the caller (unless successfully
+> resolved by an internal retry).
+
+```mermaid
+sequenceDiagram
+ participant App
+ participant Provider as GACAppAttestProvider
+ participant Apple as DCAppAttestService
(Apple's DeviceCheck Framework)
+ participant API as GACAppAttestAPIService
+ participant Backend as Firebase Backend
+
+ App->>Provider: getToken(limitedUse)
+
+ loop Retry Loop (Max 1 Retry for GACAppAttestRejectionError)
+ Provider->>Provider: Retrieve Key ID & Artifact
+ Provider->>API: getRandomChallenge()
+ API->>Backend: POST /generateAppAttestChallenge
+ Backend-->>API: { "challenge": "..." }
+ API-->>Provider: Challenge
+
+ Provider->>Provider: ClientData = Artifact + Challenge
+ Provider->>Apple: generateAssertion(keyId, clientDataHash=SHA256(ClientData))
+
+ alt Assertion Failed (Invalid Key/Input)
+ Apple-->>Provider: DCErrorInvalidKey / Input
+ Provider->>Provider: RESET: Delete KeyID & Artifact
+ Note right of Provider: Throws GACAppAttestRejectionError,
Triggering Loop Retry
(Will fall back to Initial Handshake)
+ else Assertion Success
+ Apple-->>Provider: Assertion Object
+
+ Provider->>API: getAppCheckTokenWithArtifact(..., limitedUse)
+ API->>Backend: POST /exchangeAppAttestAssertion
{ limited_use: true/false }
+ Backend-->>API: { "token": "..." }
+
+ Provider-->>App: App Check Token
+ end
+ end
+```
\ No newline at end of file
diff --git a/docs/providers/debug.md b/docs/providers/debug.md
new file mode 100644
index 00000000..82c71747
--- /dev/null
+++ b/docs/providers/debug.md
@@ -0,0 +1,30 @@
+# Debug Provider (`GACAppCheckDebugProvider`)
+
+Used for local development and CI.
+
+## Configuration
+The provider looks for a debug secret in the following order:
+1. **Environment Variable:** `AppCheckDebugToken` (or legacy
+ `FIRAAppCheckDebugToken`).
+2. **Local Storage:** `NSUserDefaults` key `GACAppCheckDebugToken`.
+3. **Generation:** If neither exists, it generates a new UUID, stores it
+ in `NSUserDefaults`, and logs it to the console (warning level).
+
+## Flow
+```mermaid
+sequenceDiagram
+ participant App
+ participant Provider as GACAppCheckDebugProvider
+ participant API as GACAppCheckDebugProviderAPIService
+ participant Backend as Firebase Backend
+
+ App->>Provider: getToken(limitedUse)
+ Provider->>Provider: Determine Debug Secret (Env Var or UUID)
+
+ Provider->>API: appCheckTokenWithDebugToken(debugToken, limitedUse)
+ API->>Backend: POST /exchangeDebugToken
{ limited_use: true/false }
+ Note right of Backend: Checks if debug token is
registered in Console.
+ Backend-->>API: { "token": "..." }
+
+ Provider-->>App: App Check Token
+```
diff --git a/docs/providers/device-check.md b/docs/providers/device-check.md
new file mode 100644
index 00000000..d43ae48e
--- /dev/null
+++ b/docs/providers/device-check.md
@@ -0,0 +1,36 @@
+# DeviceCheck Provider (`GACDeviceCheckProvider`)
+
+A simpler provider for older devices.
+
+## Components
+* **Service:** `DCDevice` (Apple's API).
+* **Generator:** `DCDevice.currentDevice`.
+
+## Flow
+```mermaid
+sequenceDiagram
+ participant App
+ participant Provider as GACDeviceCheckProvider
+ participant Apple as DCDevice
(Apple's DeviceCheck Framework)
+ participant API as GACDeviceCheckAPIService
+ participant Backend as Firebase Backend
+
+ App->>Provider: getToken(limitedUse)
+
+ Note right of Provider: Wrapped in Backoff Wrapper
+ Provider->>Apple: generateToken()
+ Apple-->>Provider: Device Token (Ephemeral)
+
+ Provider->>API: appCheckTokenWithDeviceToken(deviceToken, limitedUse)
+ API->>Backend: POST /exchangeDeviceCheckToken
{ limited_use: true/false }
+ Note right of Backend: Verifies device token with Apple.
+
+ alt Error (e.g., 503)
+ Backend-->>API: 503 Service Unavailable
+ Provider->>Provider: Record Failure (Backoff)
+ Provider-->>App: Error
+ else Success
+ Backend-->>API: { "token": "..." }
+ Provider-->>App: App Check Token
+ end
+```
diff --git a/docs/usage.md b/docs/usage.md
new file mode 100644
index 00000000..c7a79176
--- /dev/null
+++ b/docs/usage.md
@@ -0,0 +1,144 @@
+# Core Integration and Usage
+
+## Initialization
+
+To use `AppCheckCore`, you first need to initialize an `AppCheckCoreProvider` implementation (e.g., `AppCheckCoreAppAttestProvider`) and then use it to initialize `AppCheckCore`.
+
+### Swift
+```swift
+import AppCheckCore
+import Foundation
+
+// 1. Initialize an App Check Provider
+// Replace "my-sdk" with your SDK's unique identifier.
+// Replace "projects/123/apps/abc" with your actual resource name.
+// Set baseURL and APIKey if needed, otherwise nil.
+// Provide a keychainAccessGroup if you use one.
+let provider = AppCheckCoreAppAttestProvider(serviceName: "my-sdk",
+ resourceName: "projects/123/apps/abc",
+ baseURL: nil,
+ APIKey: nil,
+ keychainAccessGroup: nil,
+ requestHooks: nil)
+
+// 2. Initialize AppCheckCore
+// You can optionally provide settings and a token delegate.
+let appCheck = AppCheckCore(serviceName: "my-sdk",
+ resourceName: "projects/123/apps/abc",
+ appCheckProvider: provider,
+ settings: AppCheckCoreSettings(), // Use default settings or provide your own
+ tokenDelegate: nil, // Provide a delegate to observe token changes
+ keychainAccessGroup: nil)
+```
+
+### Objective-C
+```objectivec
+#import
+#import
+
+// 1. Initialize an App Check Provider
+// Replace "my-sdk" with your SDK's unique identifier.
+// Replace "projects/123/apps/abc" with your actual resource name.
+// Set baseURL and APIKey if needed, otherwise nil.
+// Provide a keychainAccessGroup if you use one.
+GACAppAttestProvider *provider =
+ [[GACAppAttestProvider alloc] initWithServiceName:@"my-sdk"
+ resourceName:@"projects/123/apps/abc"
+ baseURL:nil
+ APIKey:nil
+ keychainAccessGroup:nil
+ requestHooks:nil];
+
+// 2. Initialize AppCheckCore
+// You can optionally provide settings and a token delegate.
+GACAppCheck *appCheck =
+ [[GACAppCheck alloc] initWithServiceName:@"my-sdk"
+ resourceName:@"projects/123/apps/abc"
+ appCheckProvider:provider
+ settings:[[GACAppCheckSettings alloc] init] // Use default settings or provide your own
+ tokenDelegate:nil // Provide a delegate to observe token changes
+ keychainAccessGroup:nil];
+```
+
+## Fetching Tokens
+
+`AppCheckCore` provides methods to fetch App Check tokens, both for general use and for limited-use scenarios.
+
+### Fetching a Standard App Check Token
+Use `token(forcingRefresh:completion:)` to retrieve an App Check token. The `forcingRefresh` parameter determines whether to use a cached token or request a new one. In most cases, `NO` (or `false` in Swift) should be used.
+
+### Swift
+```swift
+appCheck.token(forcingRefresh: false) { result in
+ if let token = result.token {
+ print("App Check Token: \(token.token)")
+ print("Token Expiration: \(token.expirationDate)")
+ } else if let error = result.error {
+ print("Error fetching App Check token: \(error.localizedDescription)")
+ }
+}
+```
+
+### Objective-C
+```objectivec
+[appCheck tokenForcingRefresh:NO
+ completion:^(GACAppCheckTokenResult *result) {
+ if (result.token) {
+ NSLog(@"App Check Token: %@", result.token.token);
+ NSLog(@"Token Expiration: %@", result.token.expirationDate);
+ } else if (result.error) {
+ NSLog(@"Error fetching App Check token: %@", result.error.localizedDescription);
+ }
+}];
+```
+
+### Fetching a Limited-Use App Check Token
+For scenarios where you need a token for a single, immediate request without affecting the primary token's refresh cycle, use `limitedUseToken(completion:)`.
+
+### Swift
+```swift
+appCheck.limitedUseTokenWithCompletion { result in
+ if let token = result.token {
+ print("Limited-Use App Check Token: \(token.token)")
+ } else if let error = result.error {
+ print("Error fetching limited-use App Check token: \(error.localizedDescription)")
+ }
+}
+```
+
+### Objective-C
+```objectivec
+[appCheck limitedUseTokenWithCompletion:^(GACAppCheckTokenResult *result) {
+ if (result.token) {
+ NSLog(@"Limited-Use App Check Token: %@", result.token.token);
+ } else if (result.error) {
+ NSLog(@"Error fetching limited-use App Check token: %@", result.error.localizedDescription);
+ }
+}];
+```
+
+## Token Fetching Sequence Diagram
+This diagram illustrates the typical flow when an application requests an App Check token.
+
+```mermaid
+sequenceDiagram
+ participant App
+ participant GACAppCheck
+ participant Cache
+ participant GACAppCheckProvider
+ participant AppleBackend
+
+ App->>GACAppCheck: Request Token (forcingRefresh: false)
+ GACAppCheck->>Cache: Check for valid token
+ alt Token in cache and valid
+ Cache-->>GACAppCheck: Cached Token
+ GACAppCheck-->>App: App Check Token Result
+ else Token missing or expired
+ GACAppCheck->>GACAppCheckProvider: Get Token
+ GACAppCheckProvider->>AppleBackend: Perform Attestation/Verification
+ AppleBackend-->>GACAppCheckProvider: Attestation/Verification Result
+ GACAppCheckProvider-->>GACAppCheck: New App Check Token
+ GACAppCheck->>Cache: Store New Token
+ GACAppCheck-->>App: App Check Token Result
+ end
+```
\ No newline at end of file