Line data Source code
1 : import 'package:fast_immutable_collections/fast_immutable_collections.dart';
2 : import 'package:firebase_auth/firebase_auth.dart';
3 : import 'package:google_sign_in/google_sign_in.dart';
4 :
5 : import '../../../types.dart';
6 : import '../actions/set_auth_user_data_action.dart';
7 : import '../extensions/auth_extensions.dart';
8 : import '../utils/constants/auth_provider_names.dart';
9 :
10 : class AuthService extends ReduxService {
11 2 : AuthService(
12 : {required FirebaseAuth firebase,
13 : GoogleSignIn? google,
14 : SignInWithAppleWrapper? apple})
15 : : _firebaseAuth = firebase,
16 : _googleSignIn = google,
17 : _signInWithAppleWrapper = apple;
18 :
19 : final FirebaseAuth _firebaseAuth;
20 : final GoogleSignIn? _googleSignIn;
21 : final SignInWithAppleWrapper? _signInWithAppleWrapper;
22 :
23 : // Functions to get user details, or throw if there is no current user.
24 0 : Future<String> getCurrentIdToken() => _firebaseAuth.currentUser!.getIdToken();
25 0 : String getCurrentUserId() => _firebaseAuth.currentUser!.uid;
26 :
27 : // Map FirebaseUser objects emitted by FirebaseAuth to a StoreUser action,
28 : // which can be dispatched by the store.
29 : // If the FirebaseUser or the uid field is null, create an empty StoreUser
30 : // object that will set the user field of the AppState to null.
31 1 : Stream<SetAuthUserDataAction> get streamOfSetAuthUserData {
32 1 : return _firebaseAuth
33 1 : .authStateChanges()
34 4 : .map((user) => SetAuthUserDataAction(user?.toModel()));
35 : }
36 :
37 0 : Future<AuthUserData> signInAnonymously() async {
38 0 : final userCredential = await _firebaseAuth.signInAnonymously();
39 0 : final user = userCredential.user!;
40 :
41 0 : return user.toModel();
42 : }
43 :
44 0 : Future<IdTokenResult>? getIdTokenResult() {
45 0 : return FirebaseAuth.instance.currentUser?.getIdTokenResult();
46 : }
47 :
48 0 : Future<ISet<ProvidersEnum>> retrieveProvidersFor(String email) async {
49 0 : var providerNames = await _firebaseAuth.fetchSignInMethodsForEmail(email);
50 : return providerNames
51 0 : .map<ProvidersEnum>((name) => authProviderEnumFrom[name]!)
52 0 : .toISet();
53 : }
54 :
55 0 : Future<UserCredential> signUpWithEmailAndPassword(
56 : String email, String password) =>
57 0 : _firebaseAuth.createUserWithEmailAndPassword(
58 : email: email, password: password);
59 :
60 0 : Future<UserCredential> signInWithEmailAndPassword(
61 : String email, String password) =>
62 0 : _firebaseAuth.signInWithEmailAndPassword(
63 : email: email, password: password);
64 :
65 : /// `null` in case where sign in process was aborted
66 0 : Future<GoogleSignInCredential?> getGoogleCredential() async {
67 0 : final googleSignInAccount = await _googleSignIn!.signIn();
68 : final googleSignInAuthentication =
69 0 : await googleSignInAccount?.authentication;
70 :
71 0 : return googleSignInAuthentication?.toModel();
72 : }
73 :
74 0 : Future<AuthUserData> signInWithGoogle(
75 : {required GoogleSignInCredential credential}) async {
76 0 : final AuthCredential authCredential = GoogleAuthProvider.credential(
77 0 : accessToken: credential.accessToken,
78 0 : idToken: credential.idToken,
79 : );
80 :
81 : final userCredential =
82 0 : await FirebaseAuth.instance.signInWithCredential(authCredential);
83 : // not sure why user would be null (docs don't say) so we throw if it is
84 0 : final user = userCredential.user!;
85 0 : return user.toModel();
86 : }
87 :
88 0 : Future<AuthUserData> linkGoogle(
89 : {required GoogleSignInCredential credential}) async {
90 0 : final AuthCredential authCredential = GoogleAuthProvider.credential(
91 0 : accessToken: credential.accessToken,
92 0 : idToken: credential.idToken,
93 : );
94 :
95 0 : var user = FirebaseAuth.instance.currentUser!;
96 0 : final userCredential = await user.linkWithCredential(authCredential);
97 0 : user = userCredential.user!;
98 :
99 0 : return user.toModel();
100 : }
101 :
102 0 : Future<String> getTokenForGoogle(List<String> scopes) async {
103 0 : final googleSignIn = GoogleSignIn(scopes: scopes);
104 0 : final googleSignInAccount = await googleSignIn.signIn();
105 : final googleSignInAuthentication =
106 0 : await googleSignInAccount!.authentication;
107 0 : return googleSignInAuthentication.accessToken!;
108 : }
109 :
110 0 : Future<AppleIdCredential> getAppleCredential() async {
111 : // By default, scopes = email, fullName
112 0 : final appleIdCredential = await _signInWithAppleWrapper!.getCredential();
113 :
114 0 : return appleIdCredential.toModel();
115 : }
116 :
117 0 : Future<AuthUserData> signInWithApple(
118 : {required AppleIdCredential credential}) async {
119 : // convert to OAuthCredential
120 0 : final oAuthCredential = OAuthProvider('apple.com').credential(
121 0 : idToken: credential.identityToken,
122 0 : accessToken: credential.authorizationCode,
123 : );
124 :
125 : // use the credential to sign in to firebase
126 : final userCredential =
127 0 : await FirebaseAuth.instance.signInWithCredential(oAuthCredential);
128 0 : final user = userCredential.user!;
129 :
130 0 : return user.toModel();
131 : }
132 :
133 0 : Future<UserCredential> signInWithGithubOnWeb() async {
134 : // Create a new provider
135 0 : GithubAuthProvider githubProvider = GithubAuthProvider();
136 :
137 : // Once signed in, return the UserCredential
138 0 : return await _firebaseAuth.signInWithPopup(githubProvider);
139 :
140 : // Or use signInWithRedirect
141 : // return await _firebaseAuth.signInWithRedirect(githubProvider);
142 : }
143 :
144 0 : Future<AuthUserData> signInWithGithub(String token) async {
145 0 : final credential = GithubAuthProvider.credential(token);
146 0 : final userCredential = await _firebaseAuth.signInWithCredential(credential);
147 0 : final user = userCredential.user!;
148 :
149 0 : return user.toModel();
150 : }
151 :
152 0 : Future<AuthUserData> linkGithub(String token) async {
153 0 : final credential = GithubAuthProvider.credential(token);
154 0 : final firebaseUser = _firebaseAuth.currentUser!;
155 0 : final userCredential = await firebaseUser.linkWithCredential(credential);
156 0 : final user = userCredential.user!;
157 :
158 0 : return user.toModel();
159 : }
160 :
161 : /// The stream of auth state is connected to the store at app load so the
162 : /// app state will be automatically updated.
163 0 : Future<void> signOut(ProvidersEnum? signInProvider) async {
164 0 : if (signInProvider == ProvidersEnum.google) {
165 0 : await _googleSignIn?.signOut();
166 : }
167 0 : await _firebaseAuth.signOut();
168 : }
169 : }
|