← Open Source Catalog

FireAuth Relux

SwiftUI-free Relux wrapper around FireAuthKit: auth state machine, refresh-policy service, injectable session store

View on GitHub

FireAuthRelux

A SwiftUI-free Relux wrapper around FireAuthKit: an auth state machine, a refresh-policy service, and an injectable session store, with no UI and no backend bridge.

Scope

FireAuthRelux owns the Relux pieces (State / Action / Effect / Flow), an AuthService actor that calls FireAuthKit and applies token refresh policy, and a SessionStore abstraction. The app reads State, dispatches Effect, and renders its own auth gate.

It imports no SwiftUI, no Keychain, no HTTP client, and contains no backend/profile sync. Social credential acquisition (OAuth + UI) stays in the app via FireAuthKitSocial; the app produces a FirebaseIDPCredential and dispatches signInWithCredential / upgradeAnonymousOrSignInExistingWithCredential / linkCurrentUserWithCredential.

Auth semantics (three distinct families)

These are deliberately separated so the public API cannot silently switch accounts:

FamilyMeaningOn conflict (provider/email already taken)
signIn*Authenticate as that identityn/a
upgradeAnonymousOrSignInExisting*Only valid on an anonymous session; links in placeFalls back to signing into the existing account
linkCurrentUser*Strict link onto the current userThrows: no fallback (app shows conflict/merge)

upgradeAnonymousOrSignInExisting* returns an AnonymousUpgradeOutcome:

  • .linkedAnonymousAccount: same Firebase uid; guest data still belongs to this user.
  • .signedIntoExistingAccount(previousAnonymousUserID:): an account switch; the app decides what to do with the previous guest’s local state.

This is also surfaced reactively via State.lastUpgradeMode.

The older upgradeAnonymous* effects and concrete AuthService methods are compatibility aliases for upgradeAnonymousOrSignInExisting*. Prefer linkCurrentUser* unless the app has an explicit merge flow for account switches.

State

@Observable @MainActor final class State: Relux.HybridState {
    var status: Status            // unconfigured / signedOut / restoring / signingIn /
                                  // signedIn(User) / refreshing(User) / signingOut / failed(String)
    var user: User?
    var isBusy: Bool
    var errorMessage: String?
    var emailVerified: Bool?
    var lastUpgradeMode: AnonymousUpgradeMode?
}

Effects

restoreSession, signInAnonymously, createEmailUser, signInEmail, signInWithCredential, upgradeAnonymousOrSignInExistingWithEmail, upgradeAnonymousOrSignInExistingWithCredential, linkCurrentUserWithEmail, linkCurrentUserWithCredential, refreshIfNeeded, forceRefresh, sendEmailVerification, checkEmailVerification, signOut, resetLocalAuthState.

Secrets (passwords, OAuth credentials) are redacted from Relux’s effect logging.

Session storage

public protocol SessionStore: Sendable {
    func load() async throws -> StoredSession?
    func save(_ session: StoredSession) async throws
    func clear() async throws
}

The package ships only FireAuthRelux.InMemorySessionStore. Apps provide their own (e.g. a Keychain-backed store) without the library depending on any storage SDK. StoredSession carries an explicit SessionKind (.anonymous / .authenticated), preserved across token refresh.

Module

public protocol Interface: Relux.Module {
    @MainActor var state: FireAuthRelux.Business.State { get }
    var tokenProvider: any FireAuthRelux.Business.TokenProviding { get }
}

FireAuthRelux.Module.Impl(configuration:transport:sessionStore:refreshLeeway:dispatcher:) wires the state, flow, service, and token provider. tokenProvider.bearerToken() applies the refresh policy (refreshes when the token is within refreshLeeway of expiry).

Relux integration

SwiftUI -> Relux SideEffect -> Relux Flow -> AuthService
    -> FireAuthKit -> Firebase REST

The app owns token persistence (the SessionStore), state observation, refresh timing, and any backend sync. The auth gate is app UI, not part of this package.

Installation

.package(url: "https://github.com/relux-works/FireAuthRelux.git", .upToNextMajor(from: "1.0.0"))

About Relux Works

This project is part of the open-source ecosystem of Relux Works, an AI-native software development studio. We build fixed-price MVPs, rescue vibe-coded apps, run local AI inference, and train teams to work with coding agents. Much of the infrastructure behind that work is open source.

License

MIT. See LICENSE.

MIT License

Copyright (c) 2026 Relux Works

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.