Configuring OAuth2 access token to typescript-angular2 client

删除回忆录丶 提交于 2019-12-06 05:38:30

You need to use the APP_INITIALIZER to bootstrap your API token, take a look at my answer Pass web application context to Angular2 Service to see an example of how to do that.

I think this is a swagger-codegen bug, the property signature should be

accessToken?: string | (() => Promise<string>);

Or simply

accessToken?: (() => Promise<string>);

The reason is that access tokens expire, so every time a call will be made the client should check if the token has expired and request a new one if so (token refresh), that implies an HTTP query so a promise is best option to handle access tokens. If you check Firebase's Javascript API you'll notice User.getIdToken() returns a promise because it first checks if current is expired and requests a new one if so.

So the solution I'm using meanwhile is Angular's HTTP Interceptors:

import { Injectable } from '@angular/core';
import {
  HttpEvent, HttpInterceptor, HttpHandler, HttpRequest
} from '@angular/common/http';
import { AngularFireAuth } from '@angular/fire/auth';
import * as firebase from 'firebase/app';
import { from } from 'rxjs';
import { mergeMap } from 'rxjs/operators';

import { environment } from '../environments/environment';

@Injectable({
  providedIn: 'root'
})
export class UsersApiAuthInterceptorService implements HttpInterceptor {

  constructor(private afAuth: AngularFireAuth) { }

  intercept(req: HttpRequest<any>, next: HttpHandler) {
    if (req.url.startsWith(environment.usersAPIBasePath) && this.afAuth.auth.currentUser) {
      return from(this.afAuth.auth.currentUser.getIdToken()).pipe(mergeMap(token => {
        console.log('UsersApiAuthInterceptorService got token', token);
        const authReq = req.clone({
          setHeaders: {
            Authorization: `Bearer ${token}`
          }
        });
        return next.handle(authReq);
      }));
    }
    else {
      return next.handle(req);
    }
  }
}

What I don't like about this solution is that it will intercept all HTTPClient calls and that's why I had to add if (req.url.startsWith(environment.usersAPIBasePath) ... but if all your HTTPClient calls are going to be to your API you can remove that part of the conditional.

This is how that app's providers goes in app.module.ts:

  providers: [
    ...
    { provide: BASE_PATH, useValue: environment.usersAPIBasePath },
    { provide: HTTP_INTERCEPTORS, useClass: UsersApiAuthInterceptorService, multi: true },
  ],
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!