Skip to content

Commit

Permalink
handle async tokenGetter and custom factory function
Browse files Browse the repository at this point in the history
  • Loading branch information
chenkie committed Jul 31, 2017
1 parent 25fb3f4 commit 6043327
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 20 deletions.
73 changes: 73 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,79 @@ JwtModule.forRoot({
})
```

## Using a Custom Options Factory Function

In some cases, you may need to provide a custom factory function to properly handle your configuration options. This is the case if your `tokenGetter` function relies on a service or if you are using an asynchronous storage mechanism (like Ionic's `Storage`).

Import the `JWT_OPTIONS` `InjectionToken` so that you can instruct it to use your custom factory function.

Create a factory function and specify the options as you normally would if you were using `JwtModule.forRoot` directly. If you need to use a service in the function, list it as a parameter in the function and pass it in the `deps` array when you provide the function.


```ts
import { JwtModule, JWT_OPTIONS } from '@auth0/angular-jwt';
import { TokenService } from './app.tokenservice';

// ...

export function jwtOptionsFactory(tokenService) {
return {
tokenGetter: () => {
return tokenService.getAsyncToken();
}
}
}

// ...

@NgModule({
// ...
imports: [
JwtModule.forRoot({
jwtOptionsProvider: {
provide: JWT_OPTIONS,
useFactory: jwtOptionsFactory,
deps: [TokenService]
}
})
],
providers: [TokenService]
})
```

## Configuration for Ionic 2+

The custom factory function approach described above can be used to get a token asynchronously with Ionic's `Storage`.

```ts
import { JwtModule, JWT_OPTIONS } from '@auth0/angular-jwt';
import { Storage } from '@ionic/storage';

const storage = new Storage();

export function jwtOptionsFactory() {
return {
tokenGetter: () => {
return storage.get('access_token');
}
}
}

// ...

@NgModule({
// ...
imports: [
JwtModule.forRoot({
jwtOptionsProvider: {
provide: JWT_OPTIONS,
useFactory: jwtOptionsFactory
}
})
]
})
```

## What is Auth0?

Auth0 helps you to:
Expand Down
6 changes: 4 additions & 2 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { NgModule, ModuleWithProviders, Optional, SkipSelf } from '@angular/core';
import { NgModule, ModuleWithProviders, Optional, SkipSelf, Provider } from '@angular/core';
import { JwtInterceptor } from './src/jwt.interceptor';
import { JwtHelperService } from './src/jwthelper.service';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
Expand All @@ -9,8 +9,9 @@ export * from './src/jwthelper.service';
export * from './src/jwtoptions.token';

export interface JwtModuleOptions {
jwtOptionsProvider?: Provider,
config: {
tokenGetter: () => string;
tokenGetter?: () => string | Promise<string>;
headerName?: string;
authScheme?: string;
whitelistedDomains?: Array<string | RegExp>;
Expand All @@ -36,6 +37,7 @@ export class JwtModule {
useClass: JwtInterceptor,
multi: true
},
options.jwtOptionsProvider ||
{
provide: JWT_OPTIONS,
useValue: options.config
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@auth0/angular-jwt",
"version": "1.0.0-beta.7",
"version": "1.0.0-beta.8",
"description": "JSON Web Token helper library for Angular",
"scripts": {
"prepublish": "ngc && npm run build",
Expand Down
54 changes: 37 additions & 17 deletions src/jwt.interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import {
HttpEvent,
HttpInterceptor
} from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { JwtHelperService } from './jwthelper.service';
import { JWT_OPTIONS } from './jwtoptions.token';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/fromPromise';
import 'rxjs/add/operator/mergeMap';

@Injectable()
export class JwtInterceptor implements HttpInterceptor {
tokenGetter: () => string;
tokenGetter: () => string | Promise<string>;
headerName: string;
authScheme: string;
whitelistedDomains: Array<string | RegExp>;
Expand All @@ -24,7 +26,10 @@ export class JwtInterceptor implements HttpInterceptor {
) {
this.tokenGetter = config.tokenGetter;
this.headerName = config.headerName || 'Authorization';
this.authScheme = (config.authScheme || config.authScheme === '') ? config.authScheme : 'Bearer ';
this.authScheme =
config.authScheme || config.authScheme === ''
? config.authScheme
: 'Bearer ';
this.whitelistedDomains = config.whitelistedDomains || [];
this.throwNoTokenError = config.throwNoTokenError || false;
this.skipWhenExpired = config.skipWhenExpired;
Expand All @@ -34,10 +39,14 @@ export class JwtInterceptor implements HttpInterceptor {
let requestUrl: URL;
try {
requestUrl = new URL(request.url);
return this.whitelistedDomains.findIndex(domain =>
typeof domain === 'string' ? domain === requestUrl.host :
domain instanceof RegExp ? domain.test(requestUrl.host) : false
) > -1;
return (
this.whitelistedDomains.findIndex(
domain =>
typeof domain === 'string'
? domain === requestUrl.host
: domain instanceof RegExp ? domain.test(requestUrl.host) : false
) > -1
);
} catch (err) {
// if we're here, the request is made
// to the same domain as the Angular app
Expand All @@ -46,26 +55,22 @@ export class JwtInterceptor implements HttpInterceptor {
}
}

intercept(
handleInterception(
token: string,
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const token = this.tokenGetter();
let tokenIsExpired;
) {
let tokenIsExpired: boolean;

if (!token && this.throwNoTokenError) {
throw new Error('Could not get token from tokenGetter function.');
}

if (this.skipWhenExpired) {
tokenIsExpired = token ? this.jwtHelper.isTokenExpired() : true;
tokenIsExpired = token ? this.jwtHelper.isTokenExpired(token) : true;
}

if (
token &&
tokenIsExpired &&
this.skipWhenExpired
) {
if (token && tokenIsExpired && this.skipWhenExpired) {
request = request.clone();
} else if (token && this.isWhitelistedDomain(request)) {
request = request.clone({
Expand All @@ -76,4 +81,19 @@ export class JwtInterceptor implements HttpInterceptor {
}
return next.handle(request);
}

intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
const token: any = this.tokenGetter();

if (token instanceof Promise) {
return Observable.fromPromise(token).mergeMap((asyncToken: string) => {
return this.handleInterception(asyncToken, request, next);
});
} else {
return this.handleInterception(token, request, next);
}
}
}

0 comments on commit 6043327

Please sign in to comment.