Skip to content

feat: init SwiftUI library for FirebaseAuthSwiftUI #1237

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 216 commits into from
Apr 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
216 commits
Select commit Hold shift + click to select a range
f173131
feat: init SwiftUI library for FirebaseAuthSwiftUI
russellwheatley Feb 18, 2025
51eeeef
chore: add SwiftUI example app
russellwheatley Feb 18, 2025
ce32551
chore: move library spec to root Package.swift
russellwheatley Feb 18, 2025
d0e0b13
chore: swift example app uses package locally
russellwheatley Feb 18, 2025
bb8866b
chore: init auth provider as base class
russellwheatley Feb 18, 2025
f5bef03
chore: stub providerId
russellwheatley Feb 18, 2025
37a1bd3
chore: update types
russellwheatley Feb 18, 2025
59e4741
feat: initial email provider
russellwheatley Feb 18, 2025
ecc7866
chore: started work on sign in scene
russellwheatley Feb 28, 2025
3dd1117
chore: ignore build files
russellwheatley Mar 4, 2025
3f1d3b3
refactor: update implementation to more idiomatic Swift code
russellwheatley Mar 4, 2025
f0a3811
chore: code comment
russellwheatley Mar 4, 2025
17f3bd3
initial view for email auth button
russellwheatley Mar 5, 2025
e658b54
swift example app for deving
russellwheatley Mar 5, 2025
7f02ddb
setup formatting for swiftui code
russellwheatley Mar 5, 2025
3128742
chore: initial format of all swiftui code
russellwheatley Mar 5, 2025
daa2ca3
delete initial scene not needed
russellwheatley Mar 5, 2025
1bf121b
xcode and pod config
russellwheatley Mar 5, 2025
ab18e4f
update protocol for auth provider
russellwheatley Mar 5, 2025
1d2b996
chore: update auth provider protocol
russellwheatley Mar 5, 2025
812b090
create email auth provider
russellwheatley Mar 5, 2025
20b01d5
delete unused code from example
russellwheatley Mar 5, 2025
c3ae034
format
russellwheatley Mar 5, 2025
e478b79
todo
russellwheatley Mar 6, 2025
b257f40
clean up db setup in example app
russellwheatley Mar 6, 2025
febdafc
refactor: allow users to customise content of button
russellwheatley Mar 6, 2025
2db25df
format
russellwheatley Mar 6, 2025
413578e
todo notes
russellwheatley Mar 6, 2025
fdd798c
refactor: use base class as argument
russellwheatley Mar 6, 2025
84da3e4
rename to EmailEntryView
russellwheatley Mar 6, 2025
827023b
make title customisable
russellwheatley Mar 6, 2025
76ca053
allow AuthViewPicker to modify VSStack
russellwheatley Mar 6, 2025
da4ea8f
make FUIAuth observable, update naming and throw assertion instead of…
russellwheatley Mar 6, 2025
59621e9
todo
russellwheatley Mar 6, 2025
06aa0f9
correct provider name
russellwheatley Mar 6, 2025
63a7fbb
create EmailAuthProvider
russellwheatley Mar 6, 2025
fe33ff8
warning view
russellwheatley Mar 6, 2025
27ba4d7
configureable warning view
russellwheatley Mar 6, 2025
0afd033
format
russellwheatley Mar 6, 2025
335dad7
todo
russellwheatley Mar 6, 2025
0ea278d
rm Error type
russellwheatley Mar 6, 2025
664f938
refactor: move src code into separate files
russellwheatley Mar 6, 2025
e798f99
import auth swift ui
russellwheatley Mar 7, 2025
98107e5
format
russellwheatley Mar 7, 2025
2f31c89
a configurable class is more appropriate for styling UI
russellwheatley Mar 7, 2025
7e51026
message should be configurable
russellwheatley Mar 7, 2025
2d17a9e
refactor auth picker view
russellwheatley Mar 7, 2025
224a001
refactor: use base class to configure UI
russellwheatley Mar 7, 2025
7246cd2
email auth button to be configurable
russellwheatley Mar 7, 2025
b731611
rm code moved to email package
russellwheatley Mar 7, 2025
b042566
format
russellwheatley Mar 7, 2025
e0f10d3
format
russellwheatley Mar 7, 2025
ae3bcf8
EmailAuth class
russellwheatley Mar 7, 2025
33c7832
FUIAuthFlowBase trial
russellwheatley Mar 7, 2025
114f9b3
rm button
russellwheatley Mar 7, 2025
c070be6
refactor config file
russellwheatley Mar 7, 2025
fd0aaf7
chore: format
russellwheatley Mar 7, 2025
a4ddba4
refactor email button config
russellwheatley Mar 7, 2025
9411aee
delete auth flow base
russellwheatley Mar 7, 2025
4e55802
refactor warning config
russellwheatley Mar 7, 2025
edd8319
scrub note
russellwheatley Mar 7, 2025
6917a8b
rm todo
russellwheatley Mar 7, 2025
afab989
rm unused file
russellwheatley Mar 7, 2025
7c96c31
refactor: way we render auth views
russellwheatley Mar 7, 2025
43ceb9b
import email auth ui into example
russellwheatley Mar 10, 2025
14f810a
refactor:applying styles via view modifiers
russellwheatley Mar 10, 2025
9d30841
import email auth swift
russellwheatley Mar 10, 2025
fa05d02
fix(email): imports, move util to email auth and public init
russellwheatley Mar 10, 2025
b947d7b
refactor: warning to use modifiers
russellwheatley Mar 10, 2025
2324f52
refactor: email auth button styling
russellwheatley Mar 10, 2025
223c07e
update email auth button
russellwheatley Mar 10, 2025
df83e9a
optional button modifier
russellwheatley Mar 10, 2025
fe64e28
refactor: EmailAuthButton modifiers
russellwheatley Mar 10, 2025
fb077ed
refactor: invoking auth picker
russellwheatley Mar 10, 2025
59a0dae
update example app
russellwheatley Mar 10, 2025
b927f9c
example of using callback to set view modifier
russellwheatley Mar 10, 2025
8117414
fix: stop breaking view identity
russellwheatley Mar 11, 2025
3d6b7b1
refactor: vStackStyle using ViewBuilder
russellwheatley Mar 11, 2025
04289a3
refactor: remove VStack from button, add button styling
russellwheatley Mar 11, 2025
ad0372c
feat: allow custom styling of Text within button
russellwheatley Mar 11, 2025
d71f78d
add nav back to email auth button
russellwheatley Mar 11, 2025
1d6d390
rm VStack modification until decide on how best to approach custom mo…
russellwheatley Mar 11, 2025
fa05691
refactor: use environment object to manage internal state
russellwheatley Mar 11, 2025
d612c70
chore: ensure email auth has access to global state
russellwheatley Mar 11, 2025
ac83bfb
emailentry - render View based on email validation
russellwheatley Mar 11, 2025
90edccd
inject env vars for fuiauth and global state
russellwheatley Mar 11, 2025
4f770c6
chore: example
russellwheatley Mar 11, 2025
d337532
allow default provider flows
russellwheatley Mar 11, 2025
3eb4436
refactor: move closer to preliminary design
russellwheatley Mar 21, 2025
526e760
chore: rm email package, moving to core
russellwheatley Mar 21, 2025
bbf9f7a
chore: rm Email auth package
russellwheatley Mar 21, 2025
9a73fee
fix: email utils
russellwheatley Mar 21, 2025
4596f3b
chore: tidy up auth screen
russellwheatley Mar 21, 2025
3ef9459
chore: fix up example app
russellwheatley Mar 21, 2025
20b9d47
chore: move auth flow to authEnvironment + init email provider
russellwheatley Mar 21, 2025
f80d6dd
EmailPasswordView
russellwheatley Mar 21, 2025
d85fda4
chore: pass observable to provider
russellwheatley Mar 24, 2025
b15292c
update email provider to pass authEnv and to use auth instance
russellwheatley Mar 24, 2025
393c238
update auth env to use auth instance
russellwheatley Mar 24, 2025
8278f04
chore: auth listener manager to enable removal of listener
russellwheatley Mar 24, 2025
09c8c00
chore: update email auth logic
russellwheatley Mar 24, 2025
7d7a039
update email provider to create user
russellwheatley Mar 24, 2025
712f75f
chore: create AuthConfiguration and adjust
russellwheatley Mar 25, 2025
6af2805
refactor: change provider name, and add 2 views
russellwheatley Mar 25, 2025
6bf0308
initial password recovery View
russellwheatley Mar 25, 2025
392fc14
chore: add password recovery func
russellwheatley Mar 25, 2025
c69360f
rm AuthenticationScreen
russellwheatley Mar 25, 2025
28fb71a
PasswordRecoveryView implementation
russellwheatley Mar 25, 2025
82a82b0
error message should be on local state
russellwheatley Mar 25, 2025
427d9c5
add modal after password recovery email sent
russellwheatley Mar 25, 2025
d9658c0
chore: typo in name
russellwheatley Mar 26, 2025
09b0ae0
chore: rm dismiss as not a modal
russellwheatley Mar 26, 2025
489b170
implement SignedInView
russellwheatley Mar 26, 2025
a05cf86
implement AuthPickerView logic for sign-up & login
russellwheatley Mar 26, 2025
fadaafa
change state based on login/sign up flow state
russellwheatley Mar 26, 2025
8a1e8ba
chore: remove unneeded namespace
russellwheatley Mar 26, 2025
daba588
chore: rm unneeded label
russellwheatley Mar 26, 2025
3ee359f
implement Email Sign-in View + some minor modifications
russellwheatley Mar 26, 2025
5aca980
chore: slight UI tweak
russellwheatley Mar 26, 2025
d822050
VerifyEmailView
russellwheatley Mar 26, 2025
77f151b
sign-in link correct API and rm progress loaders for now on api were …
russellwheatley Mar 27, 2025
168ee9d
chore: lower min deploy target on example app
russellwheatley Mar 27, 2025
5ee6ba5
chore: rename AuthEnvironment to AuthService
russellwheatley Mar 28, 2025
4921864
refactor: rm EmailAuthProvider
russellwheatley Mar 28, 2025
96677fa
refactor: make email auth inline with AuthPicker. rm email button
russellwheatley Mar 28, 2025
69429d4
feat: localized strings init
russellwheatley Mar 31, 2025
e0de2a1
refactor: rm unneeded additional directory
russellwheatley Mar 31, 2025
144784d
move localizable strings to correct directory
russellwheatley Mar 31, 2025
68b2c00
chore: rm Email auth as separate package
russellwheatley Mar 31, 2025
a08ec8c
chore: rm gitignore from email auth
russellwheatley Mar 31, 2025
2bfc8fb
chore: string helper functions
russellwheatley Mar 31, 2025
0de4d0e
chore: update localized strings for errors
russellwheatley Mar 31, 2025
58c1be6
update error message with localised strings
russellwheatley Apr 1, 2025
fe59877
rename to StringUtils
russellwheatley Apr 1, 2025
80a127c
chore: update swiftformatter
russellwheatley Apr 1, 2025
2a41c31
feat: init of google auth provider
russellwheatley Apr 1, 2025
69ea14d
setup provider protocol
russellwheatley Apr 1, 2025
c59aa5e
make config properties final
russellwheatley Apr 1, 2025
c37f1d4
initi google provider in auth service
russellwheatley Apr 1, 2025
1a9ba5b
format
russellwheatley Apr 1, 2025
aa8268a
google provider - init tweak
russellwheatley Apr 1, 2025
e43248f
google provider - add google signin as dep
russellwheatley Apr 1, 2025
008684d
google provider - allow no provider to be passed
russellwheatley Apr 1, 2025
7b251fe
add client id to example app
russellwheatley Apr 1, 2025
4576e40
add app delegate url handling
russellwheatley Apr 1, 2025
1456910
google provider handleUrl API
russellwheatley Apr 1, 2025
c623deb
chore: fix package.swift
russellwheatley Apr 1, 2025
98237d6
update package.swift so it validates
russellwheatley Apr 1, 2025
e3704a5
add FirebaseGoogleSwiftUI as lib to package.swift
russellwheatley Apr 1, 2025
df0f896
app project config - add google provider lib
russellwheatley Apr 1, 2025
c74a354
google provider setup for handling opening url
russellwheatley Apr 1, 2025
c580003
google provider -restructure files
russellwheatley Apr 1, 2025
fb7d515
sign in with google init
russellwheatley Apr 1, 2025
f1fcaeb
initial setup of google auth sign-in
russellwheatley Apr 1, 2025
10a6d90
google auth provider update
russellwheatley Apr 1, 2025
e922d74
google auth provider formatting
russellwheatley Apr 1, 2025
3214349
signing in with google provider
russellwheatley Apr 1, 2025
0537108
refactor: expose string utils on auth service
russellwheatley Apr 1, 2025
21423e4
facebook provider init
russellwheatley Apr 3, 2025
db2910d
facebook auth add base + add to example project
russellwheatley Apr 3, 2025
3f334e7
facebook initial setup
russellwheatley Apr 4, 2025
d8bc14a
package.resolved update
russellwheatley Apr 4, 2025
5054644
rm dead code from facebook button
russellwheatley Apr 4, 2025
db1bd8d
setup facebook button in example
russellwheatley Apr 4, 2025
28efc0f
create callback for logging in with firebase auth
russellwheatley Apr 4, 2025
2a1f4e3
add callback
russellwheatley Apr 4, 2025
c50dbd1
differentiate limitedLogin and classic login
russellwheatley Apr 7, 2025
7e08556
rename nonce to shaNonce
russellwheatley Apr 7, 2025
6e918f1
chore: handle FB login if not authorised
russellwheatley Apr 7, 2025
d4d66a7
chore: add key for tracking usage to test app
russellwheatley Apr 7, 2025
0a17292
refactor: facebook button and use LoginManager
russellwheatley Apr 7, 2025
0b0dd57
delete previous version of Facebook button
russellwheatley Apr 7, 2025
5201e52
refactor: rename back to FacebookButtonView
russellwheatley Apr 7, 2025
8880298
chore: refactor FB button
russellwheatley Apr 7, 2025
72c508a
typo
russellwheatley Apr 7, 2025
dc99e45
google button
russellwheatley Apr 8, 2025
c7d5ca9
example app setup for email links
russellwheatley Apr 9, 2025
c8b8acb
feat: email link sign-in
russellwheatley Apr 9, 2025
ab08caa
use enum for errors
russellwheatley Apr 9, 2025
a797eec
chore: move google sign-in method
russellwheatley Apr 9, 2025
4ed2a74
refactor: move facebook sign-in to provider
russellwheatley Apr 10, 2025
9daf9dd
rename google provider error enum
russellwheatley Apr 10, 2025
9c4fbd0
init phone auth package
russellwheatley Apr 10, 2025
d5d8c51
phone .gitignore
russellwheatley Apr 10, 2025
c7e73a4
delete phone auth package.swift
russellwheatley Apr 10, 2025
bee2add
update example project for phone auth
russellwheatley Apr 10, 2025
872fe7c
phone auth
russellwheatley Apr 10, 2025
6b96797
phone auth configuration
russellwheatley Apr 10, 2025
4341794
improve phone auth flow
russellwheatley Apr 11, 2025
7d23b2c
example app -disable swizzling for app delegate and add entitlement
russellwheatley Apr 11, 2025
c0d80db
auth service separate sign-in flows
russellwheatley Apr 11, 2025
7164986
only sign-in link requires action code settings
russellwheatley Apr 11, 2025
e21a3fc
note on password recovery
russellwheatley Apr 11, 2025
1983e73
auto link accounts
russellwheatley Apr 14, 2025
31087b8
add delete user and reauthenticate methods
russellwheatley Apr 14, 2025
c9fd8fe
use strings from existing FUIAuth implementation
russellwheatley Apr 14, 2025
9e23a3a
refactor: move errorMessage to auth service
russellwheatley Apr 14, 2025
9a22ef3
rm Nav links and use auth service view enum
russellwheatley Apr 16, 2025
c2ccc08
update error message
russellwheatley Apr 16, 2025
e037853
update to SignInWithAppleButton
russellwheatley Apr 16, 2025
4c4f78e
make auth config a struct
russellwheatley Apr 16, 2025
c264fe5
make exception rootViewControllerNotFound
russellwheatley Apr 16, 2025
ed274be
make auth listener private
russellwheatley Apr 16, 2025
5a38bd1
format
russellwheatley Apr 16, 2025
5c31f91
migrate to string catalog
russellwheatley Apr 16, 2025
76fa8f3
chore: update to use canonical string
russellwheatley Apr 16, 2025
2923384
move shared utils to core auth package
russellwheatley Apr 16, 2025
0d5d8ba
reduce scope of limited login binding
russellwheatley Apr 16, 2025
b92e0aa
scheme for example
russellwheatley Apr 17, 2025
16131d6
refactor: use retry reauthenticate logic and create password prompt
russellwheatley Apr 17, 2025
c58f821
clean up
russellwheatley Apr 17, 2025
9306d55
rename to SignInWithGoogleButton
russellwheatley Apr 17, 2025
cc84484
rename to SignInWithFacebookButton
russellwheatley Apr 17, 2025
bc49a21
google button clean up
russellwheatley Apr 17, 2025
dfc7e68
remove handling state already occuring in signIn
russellwheatley Apr 17, 2025
584774a
Merge branch 'main' into auth-provider-swiftui
russellwheatley Apr 23, 2025
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ DerivedData
*.hmap
*.ipa
*.xcuserstate

.build/
# Third Party
/sdk

Expand Down
5 changes: 5 additions & 0 deletions .swiftformat
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Formatting Options
--indent 2
--maxwidth 100
--wrapparameters afterfirst
--disable wrapMultilineStatementBraces
8 changes: 8 additions & 0 deletions FirebaseSwiftUI/FirebaseAuthSwiftUI/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
31 changes: 31 additions & 0 deletions FirebaseSwiftUI/FirebaseAuthSwiftUI/Sources/AuthServiceError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

import SwiftUI

public enum AuthServiceError: LocalizedError {
case invalidEmailLink
case notConfiguredProvider(String)
case clientIdNotFound(String)
case notConfiguredActionCodeSettings
case reauthenticationRequired(String)
case invalidCredentials(String)
case signInFailed(underlying: Error)

public var errorDescription: String? {
switch self {
case .invalidEmailLink:
return "Invalid sign in link. Most likely, the link you used has expired. Try signing in again."
case let .notConfiguredProvider(description):
return description
case let .clientIdNotFound(description):
return description
case .notConfiguredActionCodeSettings:
return "ActionCodeSettings has not been configured for `AuthConfiguration.emailLinkSignInActionCodeSettings`"
case let .reauthenticationRequired(description):
return description
case let .invalidCredentials(description):
return description
case let .signInFailed(underlying: error):
return "Failed to sign in: \(error.localizedDescription)"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
@preconcurrency import FirebaseAuth
import Observation

protocol EmailPasswordOperationReauthentication {
var passwordPrompt: PasswordPromptCoordinator { get }
}

extension EmailPasswordOperationReauthentication {
func reauthenticate() async throws -> AuthenticationToken {
guard let user = Auth.auth().currentUser else {
throw AuthServiceError.reauthenticationRequired("No user currently signed-in")
}

guard let email = user.email else {
throw AuthServiceError.invalidCredentials("User does not have an email address")
}

do {
let password = try await passwordPrompt.confirmPassword()

let credential = EmailAuthProvider.credential(withEmail: email, password: password)
try await Auth.auth().currentUser?.reauthenticate(with: credential)

return .firebase("")
} catch {
throw AuthServiceError.signInFailed(underlying: error)
}
}
}

class EmailPasswordDeleteUserOperation: DeleteUserOperation,
EmailPasswordOperationReauthentication {
let passwordPrompt: PasswordPromptCoordinator

init(passwordPrompt: PasswordPromptCoordinator) {
self.passwordPrompt = passwordPrompt
}
}

@MainActor
@Observable
public final class PasswordPromptCoordinator {
var isPromptingPassword = false
private var continuation: CheckedContinuation<String, Error>?

func confirmPassword() async throws -> String {
return try await withCheckedThrowingContinuation { continuation in
self.continuation = continuation
self.isPromptingPassword = true
}
}

func submit(password: String) {
continuation?.resume(returning: password)
cleanup()
}

func cancel() {
continuation?
.resume(throwing: AuthServiceError.reauthenticationRequired("Password entry cancelled"))
cleanup()
}

private func cleanup() {
continuation = nil
isPromptingPassword = false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import AuthenticationServices
import FirebaseAuth

extension NSError {
var requiresReauthentication: Bool {
domain == AuthErrorDomain && code == AuthErrorCode.requiresRecentLogin.rawValue
}

var credentialAlreadyInUse: Bool {
domain == AuthErrorDomain && code == AuthErrorCode.credentialAlreadyInUse.rawValue
}
}

enum AuthenticationToken {
case apple(ASAuthorizationAppleIDCredential, String)
case firebase(String)
}

protocol AuthenticatedOperation {
func callAsFunction(on user: User) async throws
func reauthenticate() async throws -> AuthenticationToken
func performOperation(on user: User, with token: AuthenticationToken?) async throws
}

extension AuthenticatedOperation {
func callAsFunction(on user: User) async throws {
do {
try await performOperation(on: user, with: nil)
} catch let error as NSError where error.requiresReauthentication {
let token = try await reauthenticate()
try await performOperation(on: user, with: token)
} catch AuthServiceError.reauthenticationRequired {
let token = try await reauthenticate()
try await performOperation(on: user, with: token)
}
}
}

protocol DeleteUserOperation: AuthenticatedOperation {}

extension DeleteUserOperation {
func performOperation(on user: User, with _: AuthenticationToken? = nil) async throws {
try await user.delete()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import FirebaseAuth
import Foundation

public struct AuthConfiguration {
let shouldHideCancelButton: Bool
let interactiveDismissEnabled: Bool
let shouldAutoUpgradeAnonymousUsers: Bool
let customStringsBundle: Bundle?
let tosUrl: URL
let privacyPolicyUrl: URL
let emailLinkSignInActionCodeSettings: ActionCodeSettings?
let verifyEmailActionCodeSettings: ActionCodeSettings?

public init(shouldHideCancelButton: Bool = false,
interactiveDismissEnabled: Bool = true,
shouldAutoUpgradeAnonymousUsers: Bool = false,
customStringsBundle: Bundle? = nil,
tosUrl: URL = URL(string: "https://example.com/tos")!,
privacyPolicyUrl: URL = URL(string: "https://example.com/privacy")!,
emailLinkSignInActionCodeSettings: ActionCodeSettings? = nil,
verifyEmailActionCodeSettings: ActionCodeSettings? = nil) {
self.shouldHideCancelButton = shouldHideCancelButton
self.interactiveDismissEnabled = interactiveDismissEnabled
self.shouldAutoUpgradeAnonymousUsers = shouldAutoUpgradeAnonymousUsers
self.customStringsBundle = customStringsBundle
self.tosUrl = tosUrl
self.privacyPolicyUrl = privacyPolicyUrl
self.emailLinkSignInActionCodeSettings = emailLinkSignInActionCodeSettings
self.verifyEmailActionCodeSettings = verifyEmailActionCodeSettings
}
}
Loading
Loading