Angular Tutorial: Oauth2 Login and Refresh Token

by Didin J. on Mar 06, 2023 Angular Tutorial: Oauth2 Login and Refresh Token

The comprehensive step-by-step Angular tutorial on implementing Oauth2 (Authentication) login and refresh token in front-end web app

In this Angular tutorial, we will implement the Oauth2 login and refresh token in the front-end web app. We will use our existing Node-Express-PostgreSQL Oauth2 server as the back-end. You can get the tutorial and the source code for the back end here.

This tutorial is divided into several steps:

The scenario for this tutorial is very simple. New users register to the Angular application using a username, password, and name. The registered user login to the Angular app to get an access token and refresh token. The access token and refresh token save to local storage. Every request to the secure endpoint from the secure or guarded page should contain a valid access token.

The following tools, frameworks, and modules are required for this tutorial:

  1. Node.js (can run npm or yarn)
  2. Angular
  3. Angular-CLI
  4. Node-Express-PostgreSQL-Oauth2
  5. PostgreSQL Server
  6. Terminal or Node Command Line
  7. IDE or Text Editor

We assume that you have installed the latest recommended Node.js on your computer. Let's check them by typing these commands in the terminal or Node command line.

node -v
v18.14.0
npm -v
9.5.1

You can watch the video tutorial on our YouTube channel here.

That's our Node and NPM version. Let's get started with the main steps!


Step #1: Create an Angular Application

In creating the Angular 10 application, we will use Angular-CLI. The Angular CLI is a command-line interface tool that use to initialize, develop, scaffold, and maintain Angular applications directly from a terminal or cmd. To install the Angular-CLI, type this command from the terminal and cmd.

npm install -g @angular/cli

Now, we can create a new Angular 10 application by typing this command.

ng new angular-oauth2

If you get these questions, just choose 'y' and 'SCSS'.

? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? SCSS   [ https://sass-lang.com/
documentation/syntax#scss                ]

Next, go to the newly created Angular application then check it by running the application for the first time.

cd ./angular-oauth2 && ng serve

Open the browser then go to 'localhost:4200' and you will this standard Angular welcome page.

Angular Tutorial: Oauth2 Login and Refresh Token - welcome


Step #2: Add Token and API Service

We will do any token CRUD operation in service, also, and REST API operation in a different service. For that, generate these services using Angular-CLI.

ng g service auth
ng g service token

Open and edit `src/app/token.service.ts` then add these constant variables after the imports.

const ACCESS_TOKEN = 'access_token';
const REFRESH_TOKEN = 'refresh_token';

Add these token CRUD operation functions after the constructor function.

  getToken(): string {
    return localStorage.getItem(ACCESS_TOKEN)!;
  }

  getRefreshToken(): string {
    return localStorage.getItem(REFRESH_TOKEN)!;
  }

  saveToken(token: any): void {
    localStorage.setItem(ACCESS_TOKEN, token);
  }

  saveRefreshToken(refreshToken: any): void {
    localStorage.setItem(REFRESH_TOKEN, refreshToken);
  }

  removeToken(): void {
    localStorage.removeItem(ACCESS_TOKEN);
  }

  removeRefreshToken(): void {
    localStorage.removeItem(REFRESH_TOKEN);
  }

For accessing REST API, we will use the built-in Angular feature HTTP Client module. Open and edit `src/app/app.module.ts` then add this HTTP Client module to the @NgModule import array.

  imports: [
    BrowserModule,
    HttpClientModule,
    AppRoutingModule
  ],

Don't forget to add imports to that module.

import { HttpClientModule } from '@angular/common/http';

Next, open and edit `src/app/auth.service.ts` then declare the required OAuth client and secret and REST API URL as the constant variable.

const OAUTH_CLIENT = 'express-client';
const OAUTH_SECRET = 'express-secret';
const API_URL = 'http://localhost:3000/';

Also, add a constant variable that contains the headers for Form data and basic authorization that convert the OAuth2 client and secret to a basic auth token.

const HTTP_OPTIONS = {
  headers: new HttpHeaders({
    'Content-Type': 'application/x-www-form-urlencoded',
    Authorization: 'Basic ' + Buffer.from(OAUTH_CLIENT + ':' + OAUTH_SECRET).toString('base64')
  })
};

Before this tutorial was updated, we are using "btoa" to convert the string to base64. But btoa is deprecated now.  So, we are using Node.js Buffer as a replacement. To make the Buffer work, type this command to install it.

npm i --save-dev @types/node

Open and edit tsconfig.app.json then add "node" to the types.

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/app",
    "types": [
      "node"
    ]
  },
  "files": [
    "src/main.ts"
  ],
  "include": [
    "src/**/*.d.ts"
  ]
}

In the src/app/auth.service.ts, add this import.

import { Buffer } from 'buffer';

Declare the required variable a the top of the class body.

  redirectUrl = '';

Add the functions that handle error response and log messages before the constructor.

  private static handleError(error: HttpErrorResponse): any {
    if (error.error instanceof ErrorEvent) {
      console.error('An error occurred:', error.error.message);
    } else {
      console.error(
        `Backend returned code ${error.status}, ` +
        `body was: ${error.error}`);
    }
    return throwError(() => new Error('Something bad happened; please try again later.'));
  }

  private static log(message: string): any {
    console.log(message);
  }

Inject the HttpClient and TokenService to the constructor.

  constructor(private http: HttpClient, private tokenService: TokenService) {
  }

Add the required API calls after the constructor.

  login(loginData: any): Observable<any> {
    this.tokenService.removeToken();
    this.tokenService.removeRefreshToken();
    const body = new HttpParams()
      .set('username', loginData.username)
      .set('password', loginData.password)
      .set('grant_type', 'password');

    return this.http.post<any>(API_URL + 'oauth/token', body, HTTP_OPTIONS)
      .pipe(
        tap(res => {
          this.tokenService.saveToken(res.access_token);
          this.tokenService.saveRefreshToken(res.refresh_token);
        }),
        catchError(AuthService.handleError)
      );
  }

  refreshToken(refreshData: any): Observable<any> {
    this.tokenService.removeToken();
    this.tokenService.removeRefreshToken();
    const body = new HttpParams()
      .set('refresh_token', refreshData.refresh_token)
      .set('grant_type', 'refresh_token');
    return this.http.post<any>(API_URL + 'oauth/token', body, HTTP_OPTIONS)
      .pipe(
        tap(res => {
          this.tokenService.saveToken(res.access_token);
          this.tokenService.saveRefreshToken(res.refresh_token);
        }),
        catchError(AuthService.handleError)
      );
  }

  logout(): void {
    this.tokenService.removeToken();
    this.tokenService.removeRefreshToken();
  }

  register(data: any): Observable<any> {
    return this.http.post<any>(API_URL + 'oauth/signup', data)
      .pipe(
        tap(_ => AuthService.log('register')),
        catchError(AuthService.handleError)
      );
  }

  secured(): Observable<any> {
    return this.http.get<any>(API_URL + 'secret')
      .pipe(catchError(AuthService.handleError));
  }

Update the imports too.

import { HttpClient, HttpErrorResponse, HttpHeaders, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { catchError, Observable, tap, throwError } from 'rxjs';
import { TokenService } from './token.service';


Step #3: Add Angular HTTP Interceptor

Now, we need to add an Angular HTTP Interceptor that intercepts the request and response from the REST API calls. Create a new file `src/app/auth.interceptor.ts` then add these imports to that file.

import {Injectable} from '@angular/core';
import {HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse} from '@angular/common/http';
import {Router} from '@angular/router';
import {throwError} from 'rxjs';
import {TokenService} from './token.service';
import {catchError, map} from 'rxjs/operators';
import {AuthService} from './auth.service';

Add the injectable class that implements the HttpInterceptor.

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

}

Add a constructor with Router, AuthService, and TokenService parameters.

  constructor(
    private router: Router,
    private tokenService: TokenService,
    private authService: AuthService) {
  }

Add this intercept function after the constructor.

    intercept(request: HttpRequest<any>, next: HttpHandler): any {

        const token = this.tokenService.getToken();
        const refreshToken = this.tokenService.getRefreshToken();

        if (token) {
            request = request.clone({
                setHeaders: {
                    Authorization: 'Bearer ' + token
                }
            });
        }

        if (!request.headers.has('Content-Type')) {
            request = request.clone({
                setHeaders: {
                    'content-type': 'application/json'
                }
            });
        }

        request = request.clone({
            headers: request.headers.set('Accept', 'application/json')
        });

        return next.handle(request).pipe(
            map((event: HttpEvent<any>) => {
                if (event instanceof HttpResponse) {
                    console.log('event--->>>', event);
                }
                return event;
            }),
            catchError((error: HttpErrorResponse) => {
                console.log(error.error.error);
                if (error.status === 401) {
                    if (error.error.error === 'invalid_token') {
                        this.authService.refreshToken({ refresh_token: refreshToken })
                            .subscribe(() => {
                                location.reload();
                            });
                    } else {
                        this.router.navigate(['login']).then(_ => console.log('redirect to login'));
                    }
                }
                return throwError(() => new Error(error.error.error));
            }));
    }

If there's a token available, the request will intercept by headers that contain Authorization with Bearer token value and application/json content-type. Every successful response will be noted on the console log. Every error response will catch and specify if the response status is 401 (Unauthorized). Also, specified again the 401 to check the error message that contains "invalid_token". If found, then execute the refresh token API calls otherwise, it will redirect to the login page.
Register that created AuthInterceptor class to the app.module.ts inside the provider's array.

  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true
    }
  ],

Don't forget to add the imports.

import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http';
import {AuthInterceptor} from './auth.interceptor';


Step #4: Add Angular Routing and Navigation

As you see in the previous Angular creation, there is also creating a routing. So, we just need to modify the current generated routing to add the guarded or secured routes. Open this Angular project using your IDE or text editor. Before modifying the Angular routing, add these required components by typing these commands.

ng g component login
ng g component register
ng g component secure
ng g component not-found

Those commands will generate all required files (TS, HTML, SCSS) for the required components. They also added to the `src/app/app.module.ts`. Now, we can open and edit `src/app/app-routing.module.ts`. Modify the blank route array to be like this.

const routes: Routes = [
  { path: '', redirectTo: 'secure', pathMatch: 'full' },
  { path: 'secure', canActivate: [ AuthGuard ], component: SecureComponent },
  { path: 'login', component: LoginComponent },
  { path: 'register', component: RegisterComponent },
  { path: '404', component: NotFoundComponent },
  { path: '**', redirectTo: '404' }
];

As you can see, there is a canActivate: [ AuthGuard ] parameter for the secure route. We can create this module later. Also, redirect to the not found page if navigating to a page other than registered routes. Using the right IDE, it will import the components automatically while typing the component name. Or you can import the component manually along with the AuthGuard module.

import { SecureComponent } from './secure/secure.component';
import { LoginComponent } from './login/login.component';
import { RegisterComponent } from './register/register.component';
import { AuthGuard } from './auth.guard';
import { NotFoundComponent } from './not-found/not-found.component';

Next, generate the AuthGuard module by typing this command.

ng g guard auth

Then choose `CanActivate` same as the secure route parameter.

? Which interfaces would you like to implement? (Press <space> to select, <a> to
 toggle all, <i> to invert selection)
?? CanActivate
 ? CanActivateChild
 ? CanDeactivate
 ? CanLoad

Open and edit `src/app/auth.guard.ts` then remove the CanActivate implementation because this implementation is deprecated in Angular 15+. 

export class AuthGuard {
...
}

Inject AuthService, TokenService, and Router to the constructor.

constructor(private authService: AuthService, private tokenService: TokenService, private router: Router) {
  }

Modify the canActivate() function to be like this.

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): boolean {
    const url: string = state.url;

    return this.checkLogin(url);
  }

Add a function to check if the user login or not.

  checkLogin(url: string): boolean {
    if (this.tokenService.getRefreshToken()) {
      return true;
    }

    this.authService.redirectUrl = url;

    this.router.navigate(['/login']).then(() => console.log('Redirect to login'));

    return false;
  }

Update all imports to be like this.

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
import { AuthService } from './auth.service';
import { TokenService } from './token.service';


Step #5: Implementing Login, Register, and Secure Page

We will use Angular Material to build UI/UX for this secure Angular 10 and Oauth2 application. First, install all required Angular modules and schematics.

ng add @angular/material

If there are questions like those below, just use the default answer.

? Choose a prebuilt theme name, or "custom" for a custom theme: Indigo/Pink     
   [ Preview: https://material.angular.io?theme=indigo-pink ]
? Set up global Angular Material typography styles? No
? Set up browser animations for Angular Material? Yes

We will register all required Angular Material components or modules to `src/app/app.module.ts`. Open and edit that file then add these required imports of Angular Material components, forms, and reactive form module.

import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {MatInputModule} from '@angular/material/input';
import {MatPaginatorModule} from '@angular/material/paginator';
import {MatSortModule} from '@angular/material/sort';
import {MatButtonModule} from '@angular/material/button';
import {MatCardModule} from '@angular/material/card';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
import {MatTableModule} from '@angular/material/table';
import {MatIconModule} from '@angular/material/icon';

Register those modules to `@NgModule` imports.

  imports: [
    ...
    FormsModule,
    ReactiveFormsModule,
    MatInputModule,
    MatPaginatorModule,
    MatProgressSpinnerModule,
    MatSortModule,
    MatTableModule,
    MatIconModule,
    MatButtonModule,
    MatCardModule,
    MatFormFieldModule
  ],

Next, open and edit `src/app/login/login.component.ts` then add these imports.

import { Component, OnInit } from '@angular/core';
import {AuthService} from '../auth.service';
import {ErrorStateMatcher} from '@angular/material/core';
import {FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Validators} from '@angular/forms';
import {Router} from '@angular/router';

Add a class that implements ErrorStateMatcher before the @Component.

export class MyErrorStateMatcher implements ErrorStateMatcher {
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
    const isSubmitted = form && form.submitted;
    return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
  }
}

Modify @Component to use the same SCSS file `app.component.scss`.

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['../app.component.scss']
})

Add all required variables before the constructor.

  loginForm: FormGroup;
  username = '';
  password = '';
  isLoadingResults = false;
  matcher = new MyErrorStateMatcher();

Inject the AuthService, Router, and FormBuilder to the constructor. Also, build the loginForm in the constructor body.

  constructor(private authService: AuthService, private router: Router, private formBuilder: FormBuilder) {
    this.loginForm = this.formBuilder.group({
      username : [null, Validators.required],
      password : [null, Validators.required]
    });
  }

Add a function to submit the login form.

  onFormSubmit(): void {
    this.isLoadingResults = true;
    this.authService.login(this.loginForm.value)
      .subscribe(() => {
        this.isLoadingResults = false;
        this.router.navigate(['/secure']).then(_ => console.log('You are secure now!'));
      }, (err: any) => {
        console.log(err);
        this.isLoadingResults = false;
      });
  }

That submit function will call the login function from AuthService then navigate to the secure page on successful login or print the error to the console if API calls an error. Next, open and edit `src/app/login/login.component.html` then replace the default HTML template with this Angular Material template that contains the login form components.

<div class="example-container mat-elevation-z8">
    <div class="example-loading-shade" *ngIf="isLoadingResults">
        <mat-spinner *ngIf="isLoadingResults"></mat-spinner>
    </div>
    <mat-card class="example-card">
        <form [formGroup]="loginForm" (ngSubmit)="onFormSubmit()">
            <h2>Log In</h2>
            <mat-form-field class="example-full-width">
                <label>
                    <input matInput placeholder="Username" formControlName="username" [errorStateMatcher]="matcher">
                </label>
                <mat-error *ngIf="loginForm.hasError('username') && !loginForm.hasError('required')">
                    <span>Please enter Username</span>
                </mat-error>
            </mat-form-field>
            <mat-form-field class="example-full-width">
                <label>
                    <input type="password" matInput placeholder="Password" formControlName="password"
                        [errorStateMatcher]="matcher">
                </label>
                <mat-error *ngIf="loginForm.hasError('password') && !loginForm.hasError('password')">
                    <span>Please enter Password</span>
                </mat-error>
            </mat-form-field>
            <div class="button-row">
                <button type="submit" [disabled]="!loginForm.valid" mat-flat-button
                    color="primary"><mat-icon>login</mat-icon>Login</button>
            </div>
            <div class="button-row">
                <h4>Don't have an account?</h4>
            </div>
            <div class="button-row">
                <a mat-flat-button color="primary"
                    [routerLink]="['/register']"><mat-icon>how_to_reg</mat-icon>Register</a>
            </div>
        </form>
    </mat-card>
</div>

Next, open and edit `src/app/register/register.component.ts` then replace the imports with this.

import { Component, OnInit } from '@angular/core';
import {ErrorStateMatcher} from '@angular/material/core';
import {FormBuilder, FormControl, FormGroup, FormGroupDirective, NgForm, Validators} from '@angular/forms';
import {AuthService} from '../auth.service';
import {Router} from '@angular/router';

Add a class that implements ErrorStateMatcher before the @Component.

export class MyErrorStateMatcher implements ErrorStateMatcher {
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
    const isSubmitted = form && form.submitted;
    return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
  }
}

Modify @Component to use the same SCSS file `app.component.scss`.

@Component({
  selector: 'app-register',
  templateUrl: './register.component.html',
  styleUrls: ['../app.component.scss']
})

Add all required variables before the constructor.

  registerForm: FormGroup;
  username = '';
  password = '';
  name = '';
  isLoadingResults = false;
  matcher = new MyErrorStateMatcher();

Inject the AuthService, Router, and FormBuilder to the constructor. Also, build the FormGroup inside the constructor.

  constructor(private authService: AuthService, private router: Router, private formBuilder: FormBuilder) {
    this.registerForm = this.formBuilder.group({
      username : [null, Validators.required],
      password : [null, Validators.required],
      name : [null, Validators.required]
    });
  }

Add a function to submit the login form.

  onFormSubmit(): void {
    this.isLoadingResults = true;
    this.authService.register(this.registerForm.value)
      .subscribe((res: any) => {
        this.isLoadingResults = false;
        this.router.navigate(['/login']).then(_ => console.log('You are registered now!'));
      }, (err: any) => {
        console.log(err);
        this.isLoadingResults = false;
      });
  }

That submit function will call the register function from AuthService then navigate to the login page on successful registration or print the error to the console if API calls an error. Next, open and edit `src/app/register/register.component.html` then replace the default HTML template with this Angular Material template that contains the register form components.

<div class="example-container mat-elevation-z8">
    <div class="example-loading-shade" *ngIf="isLoadingResults">
        <mat-spinner *ngIf="isLoadingResults"></mat-spinner>
    </div>
    <mat-card class="example-card">
        <form [formGroup]="registerForm" (ngSubmit)="onFormSubmit()">
            <h2>Register</h2>
            <mat-form-field class="example-full-width">
                <label>
                    <input matInput placeholder="Username" formControlName="username" [errorStateMatcher]="matcher">
                </label>
                <mat-error *ngIf="registerForm.hasError('username') && !registerForm.hasError('required')">
                    <span>Please enter Username</span>
                </mat-error>
            </mat-form-field>
            <mat-form-field class="example-full-width">
                <label>
                    <input type="password" matInput placeholder="Password" formControlName="password"
                        [errorStateMatcher]="matcher">
                </label>
                <mat-error *ngIf="registerForm.hasError('password') && !registerForm.hasError('password')">
                    <span>Please enter Password</span>
                </mat-error>
            </mat-form-field>
            <mat-form-field class="example-full-width">
                <label>
                    <input matInput placeholder="Name" formControlName="name" [errorStateMatcher]="matcher">
                </label>
                <mat-error *ngIf="registerForm.hasError('name') && !registerForm.hasError('name')">
                    <span>Please enter Name</span>
                </mat-error>
            </mat-form-field>
            <div class="button-row">
                <button type="submit" [disabled]="!registerForm.valid" mat-flat-button
                    color="primary"><mat-icon>how_to_reg</mat-icon>Register</button>
            </div>
            <div class="button-row">
                <h4>Already registered?</h4>
            </div>
            <div class="button-row">
                <a mat-flat-button color="primary" [routerLink]="['/login']"><mat-icon>login</mat-icon>Login</a>
            </div>
        </form>
    </mat-card>
</div>

Next, open and edit `src/app/secure/secure.component.ts` then replace all Typescript codes with this.

import { Component, OnInit } from '@angular/core';
import {AuthService} from '../auth.service';
import {Router} from '@angular/router';

@Component({
  selector: 'app-secure',
  templateUrl: './secure.component.html',
  styleUrls: ['../app.component.scss']
})
export class SecureComponent implements OnInit {

  message = '';
  isLoadingResults = false;

  constructor(private authService: AuthService, private router: Router) { }

  ngOnInit(): void {
    this.isLoadingResults = true;
    this.authService.secured()
      .subscribe((data: any) => {
        this.message = data;
        console.log(data);
        this.isLoadingResults = false;
      });
  }

  logout(): void {
    this.authService.logout();
    this.router.navigate(['/login']).then(_ => console.log('Logout'));
  }

}

That Angular secure component load a secure REST API endpoint. If not authorized, it will redirect to the login page. Next, open and edit `src/app/secure/secure.component.html` then replace all HTML code with this.

<div class="example-container mat-elevation-z8">
  <div class="example-loading-shade"
       *ngIf="isLoadingResults">
    <mat-spinner *ngIf="isLoadingResults"></mat-spinner>
  </div>
  <mat-card class="example-card">
    <h4>{{message}}</h4>
    <div class="button-row">
      <a mat-flat-button color="primary" (click)="logout()"><mat-icon>logout</mat-icon>Logout</a>
    </div>
  </mat-card>
</div>

As you see in the previous Routes creation, there's a NotFoundComponent. We just need to modify the HTML file `src/app/not-found/not-found.component.html` and then replace all HTML tags with this.

<div class="example-container mat-elevation-z8">
  <mat-card class="example-card">
    <h2>The page not found!</h2>
    <h3>Back to the home page.</h3>
    <div class="button-row">
      <a mat-flat-button color="primary" [routerLink]="['/']"><mat-icon>back</mat-icon>Back</a>
    </div>
  </mat-card>
</div>

Finally, we need to modify the default `src/app/app.component.html` with this.

<div class="container">
  <router-outlet></router-outlet>
</div>

Also, the `src/app/app.component.scss` that use by other components too.

.container {
  padding: 20px;
}

.example-container {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

.example-form {
  min-width: 150px;
  max-width: 500px;
  width: 100%;
}

.example-full-width {
  width: 100%;
}

.example-full-width:nth-last-child(0) {
  margin-bottom: 10px;
}

.button-row {
  margin: 10px 0;
  mat-icon {
    margin-right: 10px;
  }
}

.mat-flat-button {
  width: 120px;
  margin: 5px;
}


Step #6: Run and Test Angular Oauth2 Login and Refresh Token

To make this Angular OAuth2 application work, first, run the PostgreSQL server on your machine then clone the Node-Express-Postgresql-OAuth2. Change your PostgreSQL connection in the config.json file. Then run this command to migrate the database.

cd NodeApps/express-oauth2-postgre
npm i -g sequelize-cli
sequelize db:migrate

Now, run the OAuth2 server by typing this command.

nodemon

Set the OAuth2 client for this Angular application using CURL or Postman.

curl --location 'http://localhost:3000/oauth/set_client' \
--header 'Content-Type: application/json' \
--data '{
    "clientId": "express-client",
    "clientSecret": "express-secret",
    "redirectUris": "http://localhost:3000/oauth/callback",
    "grants": ["password", "refresh_token"]
}'

Next, run the Angular application in the separate terminal tab.

cd AngularApps/angular-oauth2
ng serve

And here we go, the full Angular and OAuth2 application.

Angular Tutorial: Oauth2 Login and Refresh Token - login

Angular Tutorial: Oauth2 Login and Refresh Token - register

Angular Tutorial: Oauth2 Login and Refresh Token - secure

That it's, the Angular Tutorial: Oauth2 Login and Refresh Token. You can get the full source code from our GitHub.

If you don’t want to waste your time design your own front-end or your budget to spend by hiring a web designer then Angular Templates is the best place to go. So, speed up your front-end web development with premium Angular templates. Choose your template for your front-end project here.

That just the basic. If you need more deep learning about Angular and Typescript, you can take the following cheap course:

Thanks!

Loading…