---
id: "customers/authentication-ios"
title: "Add authentication to your iOS app"
description: "This article shows you how to add authentication to your iOS app. You'll turn on authentication in the RevenueCat SDK, listen for authentication events, and send the ID token from your identity provider to RevenueCat after each sign-in. By the end, RevenueCat will identify each Customer from a verified ID token, and your app will hold a RevenueCat access token for that Customer."
permalink: "/docs/customers/authentication-ios"
slug: "authentication-ios"
version: "current"
original_source: "docs/customers/authentication-ios.mdx"
---

> **AI agents:** This is the Markdown version of a RevenueCat documentation page. For the complete documentation index, see [llms.txt](https://www.revenuecat.com/docs/llms.txt).

This article shows you how to add authentication to your iOS app. You'll turn on authentication in the RevenueCat SDK, listen for authentication events, and send the ID token from your identity provider to RevenueCat after each sign-in. By the end, RevenueCat will identify each Customer from a verified ID token, and your app will hold a RevenueCat access token for that Customer.

:::info[Private beta]

Authentication is in private beta, and its API can change before the general release. [Tell us about your use case](https://revenuecateventfeedback.typeform.com/to/bzxYhAjZ) to get early access, and talk to your RevenueCat contact before you use it in a production app.

:::

## Prerequisites

- An [authentication method](https://www.revenuecat.com/docs/customers/authentication-methods) in your RevenueCat project for the identity provider that your app uses
- The RevenueCat iOS SDK version 5.88.0 or later, [installed](https://www.revenuecat.com/docs/getting-started/installation/ios) in your app
- Sign-in with your identity provider working in your app, so that your app can get an ID token
- Read [Authentication](https://www.revenuecat.com/docs/customers/customer-authentication) for how the identity provider, the method, and the access token fit together

## 1. Turn on authentication in the SDK

Import the SDK with `@_spi(Internal)`, then set `iamEnabled` to `true` when you configure the SDK.

```swift
// Authentication is behind an internal flag during the beta
@_spi(Internal) import RevenueCat

let configuration = Configuration.Builder(withAPIKey: revenueCatAPIKey)
    .with(iamEnabled: true)

Purchases.configure(with: configuration.build())
```

If your app uses RevenueCat from app extensions, such as widgets, configure the SDK with `.with(iamEnabled: true, keychainAccessGroup: "<YOUR_KEYCHAIN_ACCESS_GROUP>")` instead. The SDK stores the session in that keychain access group, so your app and its extensions share the same Customer.

When the SDK initializes, it creates an anonymous Customer and starts a session for that Customer. Each sign-in that follows attaches an identity to the Customer. See [Anonymous Customers and identities](https://www.revenuecat.com/docs/customers/customer-authentication#anonymous-customers-and-identities).

## 2. Listen for authentication events

Set a delegate on `Purchases.shared.authentication` to learn when the SDK updates the access token, and when refreshing it fails. Errors from an explicit `logIn(using:)` call go to its completion handler instead of the delegate.

```swift
final class AuthenticationObserver: NSObject, AuthenticationDelegate {
    // The SDK calls this method when refreshing the access token fails
    // outside of an explicit logIn(using:) call
    func authenticatorDidEncounterError(_ error: PublicError) {
        // Treat earlier access tokens as invalid, and ask the Customer to sign in again
    }

    // Optional. The SDK calls this method each time it updates the access token.
    func authenticatorDidUpdateAccessToken(_ newAccessToken: String?) {
        // Send the new access token to your backend, if it needs one
    }
}

// The SDK doesn't retain its delegate. Keep a strong reference, such as a property
// on your app delegate, for as long as you want to receive events.
let authenticationObserver = AuthenticationObserver()
Purchases.shared.authentication.delegate = authenticationObserver
```

The SDK keeps only a weak reference to the delegate. Your app must keep a strong reference to it, or the delegate is released and stops receiving events.

Most apps don't need to read the access token, because the SDK sends it with each of its own requests. Read it when your app calls your own backend, so that the backend can [verify the token](https://www.revenuecat.com/docs/customers/authentication-backend) and identify the Customer. To read the current access token at any time, use `currentAccessToken`:

```swift
let accessToken = Purchases.shared.authentication.currentAccessToken
```

## 3. Send the ID token after each sign-in

After your identity provider signs the Customer in, pass its ID token to `Purchases.shared.authentication.logIn(using:)`. RevenueCat verifies the token against your authentication method and returns an access token. RevenueCat never receives the Customer's password, only the ID token.

Pick the tab for the provider of your authentication method. The iOS SDK doesn't support Google ID sign-in yet.

#### Apple ID

Apple returns the ID token as `Data`, so you can pass it to RevenueCat as it is.

```swift
import AuthenticationServices
import SwiftUI

SignInWithAppleButton(.signIn) { request in
    request.requestedScopes = [.email]
} onCompletion: { result in
    switch result {
    case .success(let authorization):
        guard let credential = authorization.credential as? ASAuthorizationAppleIDCredential,
              let tokenData = credential.identityToken else {
            // Apple did not return an ID token
            return
        }
        Purchases.shared.authentication.logIn(using: .signInWithApple(tokenData)) { _, error in
            if let error {
                // Show an authentication error to the Customer
                return
            }
            // The Customer is now identified
        }
    case .failure(let error):
        // Show a sign-in error to the Customer
        break
    }
}
```

#### Firebase

This example uses the [Firebase iOS SDK](https://github.com/firebase/firebase-ios-sdk) and signs the Customer in with an email address and a password. Enable the **Email/Password** provider under **Authentication → Sign-in method** in the Firebase console first. Every Firebase sign-in method returns the same kind of ID token, so the call to RevenueCat stays the same for the others. To create an account instead, call `Auth.auth().createUser(withEmail:password:)`.

```swift
import FirebaseAuth

Auth.auth().signIn(withEmail: email, password: password) { result, error in
    if let error {
        // Show a sign-in error to the Customer
        return
    }

    result?.user.getIDToken { idToken, error in
        guard let idToken else {
            // Firebase did not return an ID token
            return
        }

        // Firebase returns the ID token as a String. Convert it to Data.
        Purchases.shared.authentication.logIn(using: .firebase(Data(idToken.utf8))) { _, error in
            if let error {
                // Show an authentication error to the Customer
                return
            }
            // The Customer is now identified
        }
    }
}
```

A Firebase ID token expires after one hour. `getIDToken` refreshes the token first when it is close to its expiration, so call it again for each RevenueCat sign-in instead of storing the token. Password changes, password resets, and email verification stay in Firebase.

#### OpenID Connect

This example uses Supabase, with the [Supabase Swift SDK](https://github.com/supabase/supabase-swift), and signs the Customer in with an email address and a password. Supabase returns an access token instead of a separate ID token, and that access token is the token to send to RevenueCat. Before you start, make sure that your Supabase project signs its tokens with an asymmetric key. See [Example issuer URLs](https://www.revenuecat.com/docs/customers/authentication-methods#example-issuer-urls).

```swift
import Supabase

// Create the client once, when the app starts. The anon key is safe to ship in your app.
let supabase = SupabaseClient(
    supabaseURL: URL(string: "https://<YOUR_PROJECT_REF>.supabase.co")!,
    supabaseKey: "<YOUR_SUPABASE_ANON_KEY>"
)

do {
    let session = try await supabase.auth.signIn(email: email, password: password)

    // Supabase returns an access token, not an ID token. Send it in place of the ID token.
    let token = session.accessToken

    Purchases.shared.authentication.logIn(using: .oidc(Data(token.utf8))) { _, error in
        if let error {
            // Show an authentication error to the Customer
            return
        }
        // The Customer is now identified
    }
} catch {
    // Show a sign-in error to the Customer
}
```

To create an account instead, call `supabase.auth.signUp(email:password:)`. If your project requires email confirmation, the Customer has no session until they confirm their email address. To read the current token later, use `try await supabase.auth.session.accessToken`. Supabase refreshes the token first when it is close to its expiration, so read it again for each RevenueCat sign-in instead of storing it.

## 4. Verify the sign-in

Sign in to your app with a test account. The `logIn(using:)` completion handler returns no error, and `Purchases.shared.authentication.currentAccessToken` returns an access token.

If an existing Customer already has the identity that you signed in with, RevenueCat merges the anonymous Customer into the existing one. The purchases of both Customers stay with the existing Customer.

## Limitations

- Authentication needs iOS SDK version 5.88.0 or later. The feature is behind an internal flag. We are working on support for Android, and support for the hybrid SDKs will follow.
- Your app must get an ID token from your identity provider before it can authenticate with RevenueCat. RevenueCat does not show a login screen in your app.

## Next steps

- [Verify access tokens on your backend](https://www.revenuecat.com/docs/customers/authentication-backend) to protect the calls between your app and your backend
- [Spend in-app currency from your app](https://www.revenuecat.com/docs/offerings/virtual-currency#spending-from-your-app) now that the Customer is authenticated
- [Authentication](https://www.revenuecat.com/docs/customers/customer-authentication) for how the identity provider, the method, and the access token fit together
