Angular-oauth2-oidc: Using localStorage not working as expected

Created on 17 May 2018  路  3Comments  路  Source: manfredsteyer/angular-oauth2-oidc

I'm trying to use localStorage as a backing store to make sure new tabs in the same browser have instant access to access tokens if available. I find however that it always sends Authorization: bearer null.

I'm mostly mimicking what's in the example (configuration wise). Here's a repro:

# Angular 5 CLI so using 3.x version of the lib
ng new store-test --minimal 
npm i angular-oauth2-oidc@^3 --save

Add these to the module:

HttpClientModule,
OAuthModule.forRoot({
  resourceServer: {
    allowedUrls: ['https://httpbin.org/'],
    sendAccessToken: true
  }
})

And change the component to:

import { Component } from '@angular/core';
import { AuthConfig, OAuthService, JwksValidationHandler, OAuthErrorEvent } from 'angular-oauth2-oidc';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-root',
  template: `<h1>Welcome!</h1>
    <p>
      <button (click)='login()'>login</button>
      <button (click)='logout()'>logout</button>
      <button (click)='ajax()'>ajax</button>
    </p>
    <h2>Your access token:</h2><p><code>{{accessToken}}</code></p>`,
  styles: []
})
export class AppComponent {
  constructor(private oauthService: OAuthService, private http: HttpClient) {
    this.oauthService.configure({
      issuer: 'http://localhost:5000',
      redirectUri: window.location.origin + '/',
      clientId: 'my-spa',
      scope: 'openid profile',
    });

    this.oauthService.tokenValidationHandler = new JwksValidationHandler();

    this.oauthService.setStorage(localStorage);  // <-- not the desired effect?

    this.oauthService.events.subscribe(e => { 
      if (e instanceof OAuthErrorEvent) { console.error(e); } 
      else { console.warn(e) } 
    });

    this.oauthService.loadDiscoveryDocumentAndLogin();
  }

  public get accessToken() { return this.oauthService.getAccessToken(); }

  login() { this.oauthService.initImplicitFlow(); }
  logout() { this.oauthService.logOut(); }
  ajax() { this.http.get("https://httpbin.org/get").toPromise(); } // <-- this call
}

I'm hosting the IdentityServer4 sample with implicit flow. The login/logout stuff works just fine. The ajax() call however will show up like this in Chrome:

GET /get HTTP/1.1
Host: httpbin.org
Origin: http://localhost:4200
Authorization: Bearer null
etc.

Even weirder, if I do setStorage(myStore) where I have this decorator:

const myStore: OAuthStorage = {
  getItem(key) {
    const data = localStorage.getItem(key);
    console.warn('get', key, data.substring(0, 25));
    return data; 
  },
  setItem(key, data) {
    console.warn('set', key, data.substring(0, 25));
    return localStorage.setItem(key,data);
  },
  removeItem(key) {
    console.warn('remove', key);
    return localStorage.removeItem(key);
  },
};

Then I see that all get calls properly return data, never null.

Am I configuring something incorrectly? Or have I found a bug?

Most helpful comment

After some more searching I found that updating the @NgModule's providers: [...] array with this...

{ provide: OAuthStorage, useValue: localStorage },

...does the trick. This makes the setStorage(localstorage) call superfluous even, it seems.

This same fix (as well a provider for the OAuthModuleConfig constant) is needed to make the custom interceptor mentioned in the docs work properly at all.

Not sure what options are supposed to work, but either the code or the docs need a few updates. If you could provide some guidance here (and an answer for #317) then I'd be happy to fire up a PR to fix things.

All 3 comments

After some more searching I found that updating the @NgModule's providers: [...] array with this...

{ provide: OAuthStorage, useValue: localStorage },

...does the trick. This makes the setStorage(localstorage) call superfluous even, it seems.

This same fix (as well a provider for the OAuthModuleConfig constant) is needed to make the custom interceptor mentioned in the docs work properly at all.

Not sure what options are supposed to work, but either the code or the docs need a few updates. If you could provide some guidance here (and an answer for #317) then I'd be happy to fire up a PR to fix things.

Oh, this is a good finding. setStorage is a relect of older days, where we didn't have an interceptor. I think, we should deprecate it.

The next version will contain a depcreation information for this.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rbkrabbe picture rbkrabbe  路  4Comments

godhar picture godhar  路  3Comments

grzegorz-skowronski picture grzegorz-skowronski  路  3Comments

kneefer picture kneefer  路  3Comments

medokin picture medokin  路  4Comments