Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/06-concepts/11-authentication/01-get-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ This guide walks you through that, then shows how to test signing up and signing
- The Flutter SDK installed, so you can run the app.
- Docker installed and running, if your project uses a Docker Postgres. Projects on the embedded Postgres option don't need Docker.

:::note
If you run on macOS (`flutter run -d macos`), add the Keychain Sharing entitlement before testing sign-in. See [Set up authentication on macOS](./macos-authentication).
:::

## Show the sign-in screen

Your app already includes a sign-in screen. It is just turned off by default. Turn it on with two small edits to your app's `main.dart`.
Expand Down
4 changes: 4 additions & 0 deletions docs/06-concepts/11-authentication/01-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ This is equivalent to calling `restore()` followed by `validateAuthentication()`

See [Client-side authentication](./basics#client-side-authentication) for more details on how to interact with the authentication state from the client.

:::note
macOS apps need a Keychain Sharing entitlement before authentication sessions can be stored. See [Set up authentication on macOS](./macos-authentication).
:::

### Web callback page (`auth.html`)

:::note
Expand Down
4 changes: 4 additions & 0 deletions docs/06-concepts/11-authentication/02-basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,10 @@ When access is denied, Serverpod returns:

On the client side, authentication state is managed through the `FlutterAuthSessionManager`, which is accessible via `client.auth`.

:::note
On macOS, the `FlutterAuthSessionManager` stores tokens in the Keychain. New projects need a Keychain Sharing entitlement before sign-in works. See [Set up authentication on macOS](./macos-authentication).
:::

:::info
If you are building a pure Dart application using Serverpod, you can use the `ClientAuthSessionManager` declared in the `serverpod_auth_core_client` package instead of the `FlutterAuthSessionManager`. It has the same functionality, with the exception of a `authInfoListenable` getter that is tied to the Flutter framework.
:::
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ In Xcode, select the **Runner** target, go to **Signing & Capabilities**, and en

#### Enable Keychain Sharing

macOS uses `flutter_secure_storage` to securely store session data. Add the **Keychain Sharing** capability in Xcode (**Runner** > **Signing & Capabilities** > **+ Capability** > **Keychain Sharing**).
macOS uses `flutter_secure_storage` to securely store session data. Add the **Keychain Sharing** capability in Xcode (**Runner** > **Signing & Capabilities** > **+ Capability** > **Keychain Sharing**). See [Set up authentication on macOS](../../macos-authentication) for file-based setup steps and troubleshooting.

#### Initialize the FacebookSignInService

Expand Down
120 changes: 120 additions & 0 deletions docs/06-concepts/11-authentication/08-macos-authentication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
---
sidebar_label: macOS setup
description: Add the macOS Keychain Sharing entitlement your Flutter app needs so Serverpod authentication sessions persist after sign-in, including email and social providers.
---

# Set up authentication on macOS

Serverpod stores sign-in tokens in the macOS Keychain so sessions survive app restarts. Sandboxed macOS apps need a Keychain Sharing entitlement before they can read or write that data. This guide adds the entitlement to your Flutter project. It takes a few minutes and applies to every sign-in method (email, Google, Apple, and others).

## Before you start

- A Serverpod project with the [authentication module](./setup) enabled (the default when you create a project with `serverpod create`).
- A Flutter app that calls `client.auth.initialize()` on startup (included in the project template).
- Xcode installed, if you prefer adding the entitlement through the Xcode UI.

## Add the Keychain Sharing entitlement

Add the following to both entitlements files in your Flutter app:

- `macos/Runner/DebugProfile.entitlements`
- `macos/Runner/Release.entitlements`

```xml title="macos/Runner/DebugProfile.entitlements"
<key>keychain-access-groups</key>
<array/>
```

Copy the same block into `macos/Runner/Release.entitlements`.

The empty array enables Keychain access without creating a shared App Group. Leave the array empty unless you have a specific reason to add a group identifier.

Rebuild and run your app:

```bash
cd <project>_flutter
flutter run -d macos
```

## Verify

1. Sign in through any configured provider (email is the quickest to test).
2. Confirm the app shows your signed-in content without an error.
3. Stop and restart the app. The user should still be signed in.

If sign-in still fails, see [Troubleshooting](#troubleshooting).

## Advanced

### Add the entitlement in Xcode

1. Open `macos/Runner.xcworkspace` in Xcode.
2. Select the **Runner** target, then open **Signing & Capabilities**.
3. Click **+ Capability** and add **Keychain Sharing**.
4. Repeat for **Debug**, **Profile**, and **Release** build configurations if they use separate entitlements files.

Xcode writes the same Keychain Sharing entry (`keychain-access-groups`) into your entitlements files.

### Use the login keychain for local development

If you run unsigned macOS builds locally and want to avoid Keychain Sharing entitlements entirely, configure secure storage to use the login keychain instead of the Data Protection Keychain. In your app's `main.dart`, override the session manager storage:

```dart
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:serverpod_auth_core_flutter/serverpod_auth_core_flutter.dart';

client = Client(serverUrl)
..connectivityMonitor = FlutterConnectivityMonitor()
..authSessionManager = FlutterAuthSessionManager(
storage: SecureClientAuthSuccessStorage(
secureStorage: const FlutterSecureStorage(
mOptions: MacOsOptions(
usesDataProtectionKeychain: false,
),
),
),
);
```

This path requires `flutter_secure_storage` 10.3.1 or later. Projects created with `serverpod create` pin an earlier version in `pubspec.yaml` dependency overrides, so bump the override before using this option:

```yaml title="pubspec.yaml"
dependency_overrides:
flutter_secure_storage: ^10.3.1
```

The login keychain works for local development. For production macOS builds, prefer the Keychain Sharing entitlement in [Add the Keychain Sharing entitlement](#add-the-keychain-sharing-entitlement) above.

:::warning
If you add a non-empty value to `keychain-access-groups` (for example, `$(AppIdentifierPrefix)com.example.app`), Xcode may require an Apple Developer account and a provisioning profile to sign the app.
:::

## Troubleshooting

### Sign-in fails with "A required entitlement isn't present"

**Problem:** After entering valid credentials, sign-in fails with an error similar to:

```text
PlatformException(-34018, A required entitlement isn't present, ...)
```

The server accepts the login, but the Flutter app cannot save the session.

**Cause:** The macOS app is missing the Keychain Sharing entitlement (`keychain-access-groups`). When you create a project with `serverpod create`, the CLI adds network entitlements automatically, but not Keychain access.

**Resolution:** Follow [Add the Keychain Sharing entitlement](#add-the-keychain-sharing-entitlement) above. Rebuild the app after editing the entitlements files.

### Session is lost after restarting the app

**Problem:** Sign-in succeeds, but the user is signed out after closing and reopening the app.

**Cause:** The app cannot read the stored session from the Keychain, usually because the entitlement is missing or the app was not rebuilt after adding it.

**Resolution:** Confirm both entitlements files contain the Keychain Sharing entry (`keychain-access-groups`), rebuild with `flutter run -d macos`, then sign in again and restart the app.

## Related

- [Get started with authentication](./get-started): turn on the sign-in screen and test your first login
- [Authentication basics](./basics#client-side-authentication): check sign-in state and listen for auth changes on the client
- [flutter_secure_storage macOS setup](https://pub.dev/packages/flutter_secure_storage#configure-macos-version): platform details for secure storage on macOS
Loading