Skip to content

Latest commit

 

History

History
205 lines (145 loc) · 4.75 KB

api.md

File metadata and controls

205 lines (145 loc) · 4.75 KB

Authentication

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);
  }
}

CRUD

Create

Providers Name

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

Provider Object

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);

Email & Password

When using email & password, you first need to signup, then signin:

service.signup(email, password);
...
service.signin(email, password);

Signout

service.signout();

Create profile

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 };
  }
}

Read

The process to sync the store with Firestore is similar to CollectionService:

service.sync().subscribe();

Update

When you use update you're updating the profile in Firestore:

service.update({ age });

Delete

⚠️ When you use delete you're removing the user from Firebase Authentication & Firestore. Only the authenticated user can delete their account.

service.delete();

User

For more advance operation on the account, you can use the user property:

sendEmailVerification(service.user);
updatePassword(service.user, newPassword);
service.user.reload();
...

Hooks

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) {}

Roles

The FireAuthService helps you manage roles for your user.

Custom User Claims

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
  }
}

Collection Roles

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.