> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.id.me/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.id.me/_mcp/server.

# iOS communities SDK

> Integrate the IDMe iOS Communities SDK into your iOS app to enable identity verification flows.

---

> **Prerequisites**
>
> Before integrating the SDK, ensure your development environment meets the following requirements:
>
> * iOS minimum deployment target: `15.0`
> * Xcode: `16` or later
> * Swift: `5.9+`

# Adding the SDK to your project

In Xcode, go to **File > Add Package Dependencies** and enter the repository URL:

**`URL`**

```html URL
https://github.com/IDme/ios-auth-sample-code.git
```

Select version `1.0.0` or later and add `IDmeAuthSDK` to your target.

Alternatively, add the dependency directly to your `Package.swift`:

**`Example`**

```swift Example
dependencies: [
    .package(url: "https://github.com/IDme/ios-auth-sample-code.git", from: "1.0.0")
],
targets: [
    .target(
        name: "YourApp",
        dependencies: ["IDmeAuthSDK"]
    )
]
```

# Required app integration steps

Register a custom URL scheme in your app's `Info.plist` so iOS can route the OAuth callback back to your app after verification:

**`Example`**

```xml Example
<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>yourapp</string>
        </array>
    </dict>
</array>
```

The scheme must match the scheme portion of your `redirectURI`. For example, if your redirect URI is `yourapp://idme/callback`, register `yourapp` as the scheme.

# Initialization

Create an `IDmeConfiguration` with your client credentials and desired settings, then instantiate `IDmeAuth`:

**`Example`**

```swift Example
import IDmeAuthSDK

let config = IDmeConfiguration(
    clientId: "YOUR_CLIENT_ID",
    redirectURI: "yourapp://idme/callback",
    scopes: [.military],
    environment: .production
)

let idme = IDmeAuth(configuration: config)
```

### Configuration reference

| Parameter          | Type                   | Default       | Description                                          |
| ------------------ | ---------------------- | ------------- | ---------------------------------------------------- |
| `clientId`         | `String`               | —             | OAuth Client ID from IDMe                            |
| `redirectURI`      | `String`               | —             | Registered redirect URI — must match your URL scheme |
| `scopes`           | `[IDmeScope]`          | —             | Community scopes to request                          |
| `environment`      | `IDmeEnvironment`      | `.production` | `.production` or `.sandbox`                          |
| `verificationType` | `IDmeVerificationType` | `.single`     | `.single` or `.groups`                               |
| `clientSecret`     | `String?`              | `nil`         | Optional. Required by the policies endpoint if used. |

### Available scopes

| Scope             | Community                                    |
| ----------------- | -------------------------------------------- |
| `.military`       | Active duty, veterans, and military families |
| `.firstResponder` | First responders                             |
| `.nurse`          | Nurses                                       |
| `.teacher`        | Teachers and educators                       |
| `.student`        | Students                                     |

# Common usage patterns

## Starting the verification flow

Call `login(from:)` from an `async` context, passing a `UIWindow` as the presentation anchor. The SDK opens a system browser sheet (`ASWebAuthenticationSession`) for the user to verify their community membership. The sheet dismisses automatically when verification completes.

**`Example`**

```swift Example
do {
    let credentials = try await idme.login(from: window)
    // Verification complete — credentials contains access and refresh tokens
    print(credentials.accessToken)
    print(credentials.expiresAt)
} catch let error as IDmeAuthError where error == .userCancelled {
    // User dismissed the verification sheet
} catch {
    print("Verification failed: \(error.localizedDescription)")
}
```

## Retrieving community attributes

**`Example`**

```swift Example
let response = try await idme.attributes()

for attr in response.attributes {
    print("\(attr.handle): \(attr.value ?? "")")
}

for status in response.status {
    print("\(status.group): verified=\(status.verified)")
}
```

## Token management

The SDK stores credentials in the Keychain and handles token refresh automatically:

**`Example`**

```swift Example
// Get valid credentials, refreshing if they expire within 60 seconds
let creds = try await idme.credentials(minTTL: 60)

// Check expiry
if creds.isExpired {
    // Token has expired
}

if creds.expiresWithin(seconds: 300) {
    // Token expires within 5 minutes
}
```

## Fetching available policies

Discover which verification policies your organization supports:

**`Example`**

```swift Example
let policies = try await idme.policies()
for policy in policies.filter({ $0.active }) {
    print("\(policy.name) — scope: \(policy.handle)")
}
```

## Logout

**`Example`**

```swift Example
idme.logout()
```

Clears all stored credentials and tokens from the Keychain.

# Error handling

All errors are thrown as `IDmeAuthError`, a Swift enum conforming to `LocalizedError`:

**`Example`**

```swift Example
do {
    let credentials = try await idme.login(from: window)
} catch let error as IDmeAuthError {
    switch error {
    case .userCancelled:
        // User dismissed the system browser sheet
        break
    case .tokenExchangeFailed(let statusCode, let message):
        print("Token exchange failed (\(statusCode)): \(message)")
    case .stateMismatch:
        // OAuth state parameter mismatch — possible CSRF attempt
        break
    case .notAuthenticated:
        print("No stored credentials available")
    case .refreshTokenExpired:
        print("Session expired — user must log in again")
    default:
        print(error.localizedDescription)
    }
}
```