Exploring Angular2: Implementing oauth2 with token headers

As someone who is new to Angular 2, I found that things were much simpler with interceptors in version 1.*. All you had to do was add them and suddenly your headers were available everywhere, making it easy to handle requests especially when dealing with invalid tokens.

In my Angular 2 project, I am utilizing RxJs to manage my token:

  getToken(login: string, pwd: string): Observable<boolean> {

    let bodyParams = {
      grant_type: 'password',
      client_id: 'admin',
      scope: AppConst.CLIENT_SCOPE,
      username: login,
      password: pwd
    };

    let params = new URLSearchParams();
    for (let key in bodyParams) {
      params.set(key, bodyParams[key])
    }

    let headers = new Headers({'Content-Type': 'application/x-www-form-urlencoded'});
    let options = new RequestOptions({headers: headers});

    return this.http.post(AppConst.IDENTITY_BASE_URI + '/connect/token', params.toString(), options)
      .map((response: Response) => {
        let data = response.json();

        if (data) {
          this.data = data;
          localStorage.setItem('auth', JSON.stringify({
            access_token: data.access_token,
            refresh_token: data.refresh_token
          }));
          return true;
        } else {
          return false;
        }
      });
  }

Now, the challenge lies in how I can seamlessly use this token in all my requests without having to manually set the header each time. This practice is not ideal.

If any request returns a 401-error, how can I intercept it, obtain a new token, and then resume all requests just like we used to in Angular 1?

I attempted to work with JWT from this source jwt, but unfortunately, it didn't meet my requirements. In Angular 1, I was using Restangular and everything worked smoothly there, even when handling tokens manually as outlined here: https://github.com/mgonto/restangular#seterrorinterceptor.

Answer №1

If you need to customize the default http service in Angular, there are a couple of options available to you. One way is to create a new service that extends the default http service and adds additional functionality. Another option is to directly modify the default http service by extending it.

Custom Service Approach

To create a custom service, you can follow the example below:

@Injectable()
export class HttpUtils {
  constructor(private _cookieService: CookieService) { }

  public optionsWithAuth(method: RequestMethod, searchParams?: URLSearchParams): RequestOptionsArgs {
    // Implementation details here
  }

  public options(method: RequestMethod, searchParams?: URLSearchParams, header?: Headers): RequestOptionsArgs {
    // Implementation details here
  }

  public handleError(error: Response) {
    // Error handling logic here
  }
}

Usage example:

// Example usage of the custom service

This example demonstrates how to use cookies for storing and accessing tokens within the custom service.


Extending Default HTTP Service

An alternative approach is to extend the default http service as shown below:

import { Injectable } from '@angular/core';
// Other imports...

@Injectable()
export class MyHttp extends Http {

  constructor (backend: XHRBackend, options: RequestOptions) {
    super(backend, options);
  }
  
  // Additional methods and logic here

}

Add the extended http service to your @NgModule:

@NgModule({
  providers: [
    {
      provide: MyHttp,
      useFactory: (backend: XHRBackend, options: RequestOptions) => {
        return new MyHttp(backend, options);
      },
      deps: [XHRBackend, RequestOptions]
    }
  ]
})

Usage:

@Injectable()
class CustomerService {

  constructor(private _http: MyHttp) {
  }

  query(): Observable<Customer[]> {
    // Example usage of the extended http service
  }
}

Additional Functionality

For scenarios where you need to handle token refresh using a refresh token, you can implement a method like this:

private handleError (self: MyHttp, url?: string|Request, options?: RequestOptionsArgs) {
  // Token refresh logic
}

It's advisable to test these implementations thoroughly before deploying them in production.

Answer №2

The solution to the problem involving extending AuthHttp has been successfully implemented. A new method called setRoleId was added to AuthHttp in order to dynamically set a custom header (X-RoleId).

declare module 'angular2-jwt' {
  interface AuthHttp {
    setRoleId(config: {});
  }
}

AuthHttp.prototype.setRoleId = function (roleId) {
  let jsThis = <any>(this);
  jsThis.config.globalHeaders = [
          {'Content-Type': 'application/json'}, 
          {'X-RoleId': roleId}
          ];
};

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Unable to use NodeJS await/async within an object

I'm currently developing a validation module using nodeJs and I'm facing difficulties understanding why the async/await feature is not functioning correctly in my current module. Within this module, I need to have multiple exports for validation ...

Which is more efficient for rendering performance: using images, CSS gradients, or box shadows with borders?

I'm curious about improving website scroll and animation performance. Which option would be better for your mobile webapp or website: Using a repeating thin image or CSS3 gradient? or Utilizing a repeating image instead of box shadow with a borde ...

Invoking AJAX function post readystatechange

Currently, I am in the process of making an Ajax call to a server and attempting to invoke another function once the response is ready (readystatechanged). As of now, there isn't any serverside code implemented. Surprisingly, Chrome and Firefox encoun ...

Showing the number of guilds as an action displayed on the screen

I'm trying to make my bot say "Watching (number of servers it's in) servers!" with this code: const activities_list = [ "with the &help command.", "with the developers console", "with some code", "with JavaScript", client.guilds. ...

Using ES6 proxy to intercept ES6 getter functions

I have implemented a proxy to track all property access on instances of a class, demonstrated in the code snippet below: class Person { public ageNow: number; public constructor(ageNow: number) { this.ageNow = ageNow; const proxy = new Proxy( ...

The alert box is not displaying, only the text within the tags is visible

Trying to implement an alert message for logged-in users. A successful login will trigger a success message, while incorrect username or password will display an error. function showMessage(response) { if (response.statusLogged == "Success login") { ...

Submitting forms from a different router in React can pose a unique challenge

As a beginner in React, I am working on creating a simple meal app. In my App component, I am fetching meal data from an api and allowing users to click on a meal for more details. However, I am facing an issue where searching for a new meal on the detail ...

Express session not persisting following JQuery Get request

I need to save the server variable that the user inputs. Once they submit, they are directed to another page. On this new page, I check if their server exists and redirect them back if it doesn't. When I make a post request, the session is saved, and ...

Creating a fresh line using text interpolation within Angular 4 and Ionic 3

I am facing an issue with my front-end code: <p>{{ news.content }}</p> The variable news.content is stored in the Firebase DB. Is there a way to insert a new line in this text interpolation without making any changes to the front-end code (H ...

Issue with adding json_encode to the end

I am trying to add the service using jQuery.each(), but it is not working in my JavaScript code? This is the output I am getting from my PHP code: { "data": [{ "service": ["shalo", "jikh", "gjhd", "saed", "saff", "fcds"], "address": " ...

Is it possible to generate an HTML element by utilizing an array of coordinates?

I have a set of 4 x/y coordinates that looks like this: [{x: 10, y: 5}, {x:10, y:15}, {x:20, y:10}, {x:20, y:20}] Is there a way to create an HTML element where each corner matches one of the coordinates in the array? I am aware that this can be done usi ...

Issue with Mootools Ajax call and form submission

I'm dealing with a table that displays data from a database. I'm trying to implement a way to (a) delete rows from the table and (b) edit the content of a row in real-time. Deleting rows is working perfectly, but editing the content is proving to ...

I'm looking to center the map based on latitude and longitude data retrieved from a JSON file. Additionally, I want to implement functionality in vueJS that displays a popup with a name when a marker is clicked

Here is my VueJS script that fetches JSON data and displays a map: <script> new Vue({ el: '#feed' , data: { data: [], }, mounted() { this.$nextTick(function() { var self = this; var id ...

Ways to eliminate all characters preceding a certain character within an array dataset

I am currently working on parsing a comma-separated string retrieved from a web service in my application, which contains a list of user roles. My goal is to convert this string into an array using jQuery, and I have successfully achieved that. However, I ...

Amazon Banner Integration for Angular Version 4

Having some trouble getting an Amazon banner to display inside an angular material 2 card. The div appears empty and the banner is not rendering. Any idea what could be causing this issue? Below is the code snippet showcasing my attempts: <md-card clas ...

Obtain input from request payload in WCF/ADO.NET Data Service

Why are my parameters getting lost when I try to post to an ADO.NET Data Service? This is what my code looks like: [WebInvoke(Method="POST")] public int MyMethod(int foo, string bar) {...} Here's how I'm making the ajax call using prototype.js ...

Navigate to a specific moment in an HTML5 audio track by clicking on the progress bar

<html> <head> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script> <script> $(document).ready(function(){ var counter = 0; ...

Issue with Angular 2 pipe causing unexpected undefined result

Here is a JSON format that I am working with: [{ "id": 9156, "slug": "chicken-seekh-wrap", "type": "dish", "title": "Chicken Seekh Wrap", "cuisine_type": [2140] }, { "id": 9150, "slug": "green-salad", "type": "dish", "title": "Green Sala ...

Having trouble retrieving a dynamic name with Formcontrol error?

I keep encountering a typeError in this section of code <p *ngIf="formValue.controls['{{obj.name}}'].invalid, but when I manually enter it like this *ngIf="formValue.controls['uname'].invalid it works perfectly fine. What ...

The best method for quickly loading a webpage that is over 20MB in size

My website is a single-page calendar featuring a full year's worth of images. With 344 requests and a total load size of 20MB, the page consists of a simple PHP script without a database. The requests include a CSS file (15KB), 4 JS files (20KB), two ...