The FireAuthService
makes it easy to connect Firebase Authentication and Firestore.
Create an authentication store with the type of user profile:
export interface Profile {
displayName: string;
photoURL: string;
}
export interface AuthState extends FireAuthState<Profile> {}
@Injectable({ providedIn: 'root' })
@StoreConfig({ name: 'auth' })
export class AuthStore extends Store<AuthState> {
constructor() {
super(initialAuthState);
}
}
Then extend your service with FireAuthService
:
@Injectable({ providedIn: 'root' })
@CollectionConfig({ path: 'users' })
export class AuthService extends FireAuthService<AuthState> {
constructor(store: AuthStore) {
super(store);
}
}
The authentication data will be managed by Firebase Auth
, while the profile data will be managed by Firestore
.
In this case, the collection users
will be used to store the profile.
In your Query
you might want to expose the profile
key:
@Injectable({ providedIn: 'root' })
export class AuthQuery extends Query<AuthState> {
profile$ = this.select('profile');
roles$ = this.select('roles'); // check section "roles" below
constructor(protected store: AuthStore) {
super(store);
}
}
FireAuthService
provides a single method to sign in with a provider. Just type the provider you want to use as first parameter:
service.signin('apple');
When user authenticates for the first time, a document in the collection is created
If you want to add custom options on your provider, you can use the setCustomParameters
function:
import { getAuthProvider } from 'akita-ng-fire';
const provider = getAuthProvider('microsoft');
provider.setCustomParameters({ tenant: 'TENANT_ID' });
service.signin(provider);
When using email & password, you first need to signup, then signin:
service.signup(email, password);
...
service.signin(email, password);
service.signout();
By default FireAuthService
will create a document with photoURL
and displayName
. You can override this:
export class AuthService extends FireAuthService<AuthState> {
createProfile(user: User): AuthState['profile'] {
return { uid: user.uid, email: user.email };
}
}
The process to sync the store with Firestore is similar to CollectionService
:
service.sync().subscribe();
When you use update
you're updating the profile
in Firestore:
service.update({ age });
delete
you're removing the user from Firebase Authentication & Firestore. Only the authenticated user can delete their account.
service.delete();
For more advance operation on the account, you can use the user property:
sendEmailVerification(service.user);
updatePassword(service.user, newPassword);
service.user.reload();
...
Similar to CollectionService
, the FireAuthService
provides hooks for atomic updates.
onCreate(profile: S['profile'], options: WriteOptions) {}
onUpdate(profile: S['profile'], options: WriteOptions) {}
onDelete(options: WriteOptions) {}
onSignup(credentials) {}
onSignin(credentials) {}
The FireAuthService
helps you manage roles for your user.
For roles specific to the user you might want to update the CustomUserClaims
:
First update your state:
export interface Roles {
admin: boolean;
contributor: boolean;
}
export interface AuthState extends FireAuthState<Profile>, RoleState<Roles> {}
In a Cloud function using Firebase Admin SDK
:
admin.auth().setCustomUserClaims(uid, { admin: false, contributor: true });
Then inside the FireAuthService
:
export class AuthService extends FireAuthService<AuthState> {
selectRoles(user: User): Promise<AuthState['roles']> {
return getCustomClaims(user, ['admin', 'contributor']); // Fetch keys "admin" & "contributor" of the claims in the token
}
}
To store roles somewhere else you can override the method selectRoles
and implement an updateRole
method:
export class AuthService extends FireAuthService<AuthState> {
selectRoles(user: User) {
return docData<Role>(doc(this.db, `roles/${user.uid}`));
}
updateRole(role: Partial<Role>) {
return updateDoc(doc(this.db, `roles/${user.uid}`), role);
}
}
I wouldn't recommend storing the roles on the same document as the user because rules apply to the whole document. Therefore, if a user can update the profile, he can also update his role.