Auth State Management ⚙️ (For a Basic Angular App)

Daniel Kreider
Daniel Kreider - 04. Oct. 2022
  • State Managment
  • Authentication

Need a light, simple and quick way to handle auth state in your Angular app?

You've come to the right spot. 😁

welcome

Today I'm going to show you how to add auth state management to your existing Angular project - if you follow 5 simple steps.

To do this, we'll be using a very tiny Angular library called ng-simple-state.

ng-simple-state-readme

1. Install and Import

The first step is to install the package.

npm i ng-simple-state --save

And then add it to our imports.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

import { NgSimpleStateModule } from 'ng-simple-state';

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    ...
    NgSimpleStateModule.forRoot()
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

There are also initialization options that we can use to control the behavior.

For example, we can store the state in LocalStorage with a configuration flag like this.

  imports: [
    ...
    NgSimpleStateModule.forRoot({ enableLocalStorage: true })
  ],

Now that we've imported the state management package, we'll create a data type for our user object.

2. Create the user interface

This is where the Angular CLI really shines.

ng generate interface user

What you put in the new user interface file depends on the type of backend that you're using.

In my case, I'm expecting a response from the API server to look like this.

export interface User {
  id: string;
  name: string;
  email: string;
  token: string;
  tokenExpiration: string;  
}

Now we're ready to set up a store to manage authentication state.

3. Create the user store

This will be used to handle and query user state.

In my case I created a new file called user.store.ts inside the core/stores/ directory of my Angular app. You can read more about Angular Project Structure Best Practices here if you're interested.

import { Injectable } from "@angular/core";
import { User } from "@core/models/user.model";
import { NgSimpleStateBaseStore } from "ng-simple-state";
import { Observable } from "rxjs";

@Injectable()
export class UserStore extends NgSimpleStateBaseStore<User> {

    protected initialState(): User {
        return {
            active: false,
            email: '',
            name: '',
            username: '',
            token: '',
            tokenExpiration: ''
        } as User;
    }

    set(user: User) {
        this.setState(state => (user));
    }

    get(): Observable<User> {
        return this.selectState(state => state);
    }
}

4. Provide the user store

Now we'll circle back to the app.module.ts file and add our new user store to the providers list.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

import { NgSimpleStateModule } from 'ng-simple-state';
import { UserStore } from '@core/stores/user.store';

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    ...
    NgSimpleStateModule.forRoot()
  ],
  providers: [UserStore],
  bootstrap: [AppComponent]
})
export class AppModule { }

5. Authentication state management with our new store

There are 101 different ways you can use the new user store.

It all depends on how your Angular application has been designed.

But for example, let's say we want to display the user's name in the navigation bar.

Here's how you'd do it.

import { Component, OnInit } from "@angular/core";
import { AuthService } from "../services/auth.service";
import { Router } from "@angular/router";
import { environment } from "src/environments/environment";
import { UserStore } from "@core/stores/user.store";
import { Observable } from "rxjs";
import { User } from "@core/models/user.model";

@Component({
  selector: "app-navbar",
  templateUrl: "./navbar.component.html",
  styleUrls: ["./navbar.component.css"],
})
export class NavbarComponent implements OnInit {
  $user: Observable<User>;

  constructor(public userStore: UserStore) {}

  ngOnInit() {
    this.$user = this.userStore.get();
  }
}

And then inside of our component's HTML file we'd do this.

<span>Welcome back, {{ ($user | async)?.name }}</span>

Did I miss something?

And now I want to hear from you.

What do you think of using the ng-simple-state library to handle authentication state in an Angular app?

Let me know in the comments below. 👇

signature