Skip to content
Open
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
165 changes: 165 additions & 0 deletions .agents/skills/firebaseui-ios-getting-started/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
---
name: firebaseui-ios-getting-started
description: Sets up FirebaseUI for SwiftUI authentication in a consumer iOS app. Use when adding FirebaseUI-iOS auth, FirebaseAuthSwiftUI, AuthPickerView, or default FirebaseUI SwiftUI sign-in views to an app repo.
---

# FirebaseUI iOS Getting Started

Use this skill when the user wants FirebaseUI for SwiftUI authentication added to their own iOS app repo. Assume the app should use FirebaseUI's default `AuthPickerView` unless the user asks for custom auth UI.

## Default Workflow

1. Inspect the app structure before editing:
- Find the app target, bundle identifier, minimum iOS version, Swift version, package manager, and SwiftUI app entry point.
- Find existing Firebase setup: `GoogleService-Info.plist`, `FirebaseApp.configure()`, Firebase package dependencies, URL types, entitlements, and any auth UI.
- Identify the requested sign-in providers. If the user did not specify providers, default to email/password only.

2. Verify project requirements:
- iOS deployment target must be iOS 17 or newer.
- Swift language version must be Swift 6.0 or compatible with the FirebaseUI SwiftUI products.
- The app must use a `GoogleService-Info.plist` downloaded from the user's Firebase project for the exact iOS bundle ID. Do not invent Firebase config values or reuse sample config.

3. Add dependencies from Swift Package Manager:
- Package URL: `https://github.com/firebase/FirebaseUI-iOS`
- Required product: `FirebaseAuthSwiftUI`
- Add provider products only when the app uses them:
- `FirebaseAppleSwiftUI` for Sign in with Apple
- `FirebaseGoogleSwiftUI` for Google
- `FirebaseFacebookSwiftUI` for Facebook
- `FirebasePhoneAuthSwiftUI` for Phone
- `FirebaseTwitterSwiftUI` for Twitter
- `FirebaseOAuthSwiftUI` for GitHub, Microsoft, Yahoo, or custom OAuth/OIDC

4. Configure Firebase at app launch:
- Import `FirebaseCore`.
- Call `FirebaseApp.configure()` once during launch.
- For SwiftUI apps, use an `UIApplicationDelegateAdaptor` if there is no existing app delegate.

5. Create one parent-owned `AuthService`:
- Initialize it once in a parent view, not inside frequently recreated child views.
- For SwiftUI views, keep the primary owner in `@State` so the `@Observable` service persists across view updates.
- Chain provider registration methods that match the dependencies.
- Inject it with `.environment(authService)` above `AuthPickerView` and any authenticated content that needs auth state.

6. Add the default auth surface:
- Wrap authenticated app content in `AuthPickerView`.
- Open the auth sheet by setting `authService.isPresented = true`.
- Use `authService.authenticationState` and `authService.currentUser` for simple signed-in/signed-out UI.

7. Validate:
- Run the repo's normal package resolution/build command, preferably for the real app scheme.
- If there is no obvious command, inspect available schemes and run an iOS simulator build with `xcodebuild`.
- Fix compile errors caused by missing imports, package products, deployment target, or app delegate URL handling.

## Minimal Default Views Pattern

Adapt names to the user's app. Preserve any existing app delegate and Firebase setup instead of duplicating it.

```swift
import FirebaseAuthSwiftUI
import FirebaseCore
import SwiftUI

class AppDelegate: NSObject, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
FirebaseApp.configure()
return true
}
}

@main
struct YourApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

var body: some Scene {
WindowGroup {
ContentView()
}
}
}
```

```swift
import FirebaseAuth
import FirebaseAuthSwiftUI
import SwiftUI

struct ContentView: View {
@State private var authService: AuthService

init() {
_authService = State(initialValue: AuthService(configuration: AuthConfiguration())
.withEmailSignIn())
}
Comment thread
russellwheatley marked this conversation as resolved.

var body: some View {
AuthPickerView {
NavigationStack {
VStack {
Text("Authenticated")

Button("Manage Account") {
authService.isPresented = true
}

Button("Sign Out") {
Task {
try? await authService.signOut()
}
}
}
}
}
.environment(authService)
}
}
```

## Provider Setup

Only add provider setup for providers the app actually uses.

- Email/password: add `FirebaseAuthSwiftUI`, call `.withEmailSignIn()`, and ensure Email/Password is enabled in Firebase Console Authentication.
- Google: add `FirebaseGoogleSwiftUI`, call `.withGoogleSignIn()`, add the `REVERSED_CLIENT_ID` from `GoogleService-Info.plist` as a URL scheme, and route incoming URLs through `GIDSignIn.sharedInstance.handle(url)` if the app delegate handles URLs manually.
- Apple: add `FirebaseAppleSwiftUI`, call `.withAppleSignIn()`, enable Sign in with Apple in the app's capabilities/entitlements and in Firebase Console.
- Facebook: add `FirebaseFacebookSwiftUI`, call `.withFacebookSignIn()`, add `fb{app-id}` as a URL scheme, set `FacebookAppID`, `FacebookClientToken`, and `FacebookDisplayName` in `Info.plist`, and forward launch/open-url events to `ApplicationDelegate.shared`.
- Phone: add `FirebasePhoneAuthSwiftUI`, call `.withPhoneSignIn()`, enable Phone in Firebase Console. If the app has an app delegate, preserve `Auth.auth().setAPNSToken(...)`, `Auth.auth().canHandleNotification(...)`, and `Auth.auth().canHandle(url)` handling when present.
- OAuth/OIDC: add `FirebaseOAuthSwiftUI`, call `.withOAuthSignIn(...)`, and ensure the provider is configured in Firebase Console before coding the app UI.
- Email link: configure `ActionCodeSettings` with `handleCodeInApp = true`, a valid URL/domain for the Firebase project, and `setIOSBundleID(Bundle.main.bundleIdentifier!)`.

## Gotchas

- Do not proceed silently if `GoogleService-Info.plist` is missing. Ask the user to download it from Firebase Console or confirm where it lives.
- Do not hardcode sample project Firebase values, reversed client IDs, Facebook app IDs, OAuth domains, or bundle IDs.
- Do not add every FirebaseUI provider by default. Each extra provider usually requires Firebase Console and `Info.plist` or entitlement setup.
- Do not create multiple `AuthService` instances for the same auth flow. It owns presentation and authentication state; in SwiftUI, prefer a parent-owned `@State` instance unless the app already has a stronger owner for auth state.
- If app code reads `authService.currentUser?.email`, `uid`, or other `User` members, import `FirebaseAuth` in addition to `FirebaseAuthSwiftUI`.
- `AuthPickerView` already handles default navigation, account conflict resolution, MFA flows, errors, and reauthentication for built-in default views. Avoid reimplementing those unless the user asks for custom views.
- For custom views, sensitive operations such as account deletion, password updates, and MFA unenrollment can throw reauthentication errors that default views would otherwise handle.
- FirebaseUI `14.x` does not include the `FirebaseAuthSwiftUI` product, so it is not a valid fallback for this SwiftUI workflow.
- If tagged FirebaseUI releases fail under Swift 6/Xcode with package-internal concurrency errors, check the upstream FirebaseUI SwiftUI docs/sample and consider the current `main` branch only after documenting the reproducibility tradeoff.
- If Xcode package resolution gets stuck on a stale DerivedData checkout, validate with a project-local package cache, for example `xcodebuild ... -clonedSourcePackagesDirPath SourcePackages`, then remove the generated `SourcePackages` directory before finishing.
- Xcode previews may fail if a preview instantiates a view that creates `AuthService` before `FirebaseApp.configure()` runs. Fix previews by calling `if FirebaseApp.app() == nil { FirebaseApp.configure() }` in the preview setup.

## Source References

Use these when details are needed beyond this skill:

- FirebaseUI SwiftUI docs: `https://github.com/firebase/FirebaseUI-iOS/blob/main/FirebaseSwiftUI/README.md`
- FirebaseUI SwiftUI sample: `https://github.com/firebase/FirebaseUI-iOS/tree/main/samples/swiftui/FirebaseSwiftUISample`
- Firebase iOS setup: `https://firebase.google.com/docs/ios/setup`
- Firebase Auth provider setup: `https://firebase.google.com/docs/auth`

## Validation Checklist

Before finishing, confirm:

- The FirebaseUI package products match the imported modules and `.with...SignIn()` calls.
- `GoogleService-Info.plist` is included in the app target resources, not just present on disk.
- `FirebaseApp.configure()` is called once before auth UI is used.
- URL schemes and app delegate URL handling match the enabled OAuth providers.
- The app builds for an iOS simulator or the repo's normal CI build command.
- The final response names any Firebase Console steps the user must complete manually.