serhiisol / ngx-auth

Angular 16+ Authentication Module
MIT License
234 stars 47 forks source link

response 401 does not call refresh Token routes #22

Closed nimatrazmjo closed 6 years ago

nimatrazmjo commented 6 years ago

Hi there, I'm sorry for posting this here, but I am desperate. I have added ngx-auth to my project. It used to work perfectly before.

Now it does not call refresh token if the status code is 401. authentication.service.ts

import { configuration }                    from '../../../environments/.env';
import { HttpClient, HttpErrorResponse }    from '@angular/common/http';
import { Observable }                       from 'rxjs/Observable';
import { TokenService }                     from './token.service';
import { Injectable }                       from '@angular/core';
import { Token }                            from './token.model';
import { Http, Response }                   from '@angular/http';
import { AuthService }                      from 'ngx-auth';
import { Router }                           from '@angular/router';

@Injectable()

export class AuthenticationService implements AuthService {

  serverUrl = configuration.API_BASE_URL;

  constructor(
    private http: HttpClient,
    private _http: Http,
    private tokenService: TokenService,
    private router: Router
  ) { }

  /**
   * Check, if user already authorized.
   * @description Should return Observable with true or false values
   * @returns {Observable<boolean>}
   * @memberOf AuthService
   */
  public isAuthorized(): Observable<boolean> {
    return Observable.of(this.tokenService.getToken() != null);
  }

  /**
   * Get access token
   * @description Should return access token in Observable from e.g.
   * localStorage
   * @returns {Observable<string>}
   */
  public getAccessToken(): Observable<string> {
    return this.tokenService.getAccessToken();
  }

  /**
   * Function, that should perform refresh token verifyTokenRequest
   * @description Should be successfully completed so interceptor
   * can execute pending requests or retry original one
   * @returns {Observable<any>}
   */
  public refreshToken(): Observable<Token> {
    return this.tokenService
      .getRefreshToken()
      .switchMap((refreshToken: string) => {
        return this.http.post(`http://localhost:3000/refresh`, { refreshToken });
      })
      .do(this.tokenService.setToken.bind(this))
      .catch((err) => {
        this.router.navigate(['/logout']);
      });
  }

  /**
   * Function, checks response of failed request to determine,
   * whether token be refreshed or not.
   * @description Essentialy checks status
   * @param {Response} response
   * @returns {boolean}
   */
  public refreshShouldHappen(response: HttpErrorResponse): boolean {
    return response.status === 401
  }

  /**
   * Verify that outgoing request is refresh-token,
   * so interceptor won't intercept this request
   * @param {string} url
   * @returns {boolean}
   */
  public verifyTokenRequest(url: string): boolean {
    return url.endsWith('/refresh');
  }

  getImpersonateToken(): string {
    return localStorage.getItem('impersonateToken');
  }

  login(email: string, password: string, rememberMe: boolean): Observable <Token> {
    let url = this.serverUrl + "/login";
    return this._http
      .post(url, { email: email, password: password, rememberMe: rememberMe })
      .map((response: Response) => {
        return <Token>response.json();
      })
      .catch(err => {

        return Observable.throw(err);
      });
  }

  public logout() {
    let url = this.serverUrl + "/logout";
    return this.http
      .post(url, {})
      .catch(this.handleError);
  }

  register(user: any): Observable<any> {
    let url = this.serverUrl + '/user/register';
    return this.http
      .post(url, user)
      .catch(this.handleError);
  }

  resendSecurityCode(): Observable<any> {
    let url = this.serverUrl + "/resendTsaCode";
    return this.http
      .post(url, {})
      .catch(this.handleError);
  }

  submitSecurityCode(typedCode): Observable <Token> {
    let url = this.serverUrl + "/tsaCode";
    return this.http
      .post(url, { code: typedCode })
      .catch(err => {
        return Observable.throw(err);
      });
  }
  saveDevice(): Observable <any> {
    let url = this.serverUrl + "/trusted-device";
    return this.http
      .post(url, {})
      .catch(err => {
      return Observable.throw(err);
    });
  }

  forgetPasswordRequest(email: string): Observable<any> {
    let url = this.serverUrl + "/forgotPassword";
    return this.http
      .post(url, {email: email})
      .catch(this.handleError);
  }

  checkForgotPasswordToken(token: string): Observable<any> {
    let url = this.serverUrl + "/checkForgotPasswordToken/"+token;
    return this.http
        .get(url)
        .catch(err => {
            return Observable.throw(err);
        });
  }

  resetPasswordWithToken(token: string, data: Object): Observable<any> {
    let url = this.serverUrl + "/resetPassword/" + token;
    return this._http
        .post(url, data)
        .catch(this.handleError);
  }

  changeTSASettings(value: boolean): Observable<any> {
    return this.http
      .post(`${this.serverUrl}/change-tsa`, {value: value})
      .catch(this.handleError);
  }

  checkTSASettings(): Observable<any> {
    return this.http
      .get(`${this.serverUrl}/check-tsa`)
      .catch(this.handleError);
  }

  public getHeaders(token: string): { [name: string]: string | string[] } {
    if (this.getImpersonateToken() !== null) {
      return {
        'Authorization': `Bearer ${this.getImpersonateToken()}`
      }
    } else {
      return {
        'Authorization': `Bearer ${token}`
      }
    }

  }

  private handleError(error: any) {
      if(error instanceof HttpErrorResponse) {
          return Observable.throw({status: error.status, text: error.error.message, _body: error.error.message} || {status: error.status, text: "Server error"});
      }
      return Observable.throw(error || 'server error');
  }
}

Authentication.module.ts

import { NgModule } from '@angular/core';
import {
  AuthModule,
  AUTH_SERVICE,
  PUBLIC_FALLBACK_PAGE_URI,
  PROTECTED_FALLBACK_PAGE_URI
} from 'ngx-auth';

import { TokenService } from './token.service';
import { AuthenticationService } from './authentication.service';

export function factory(authenticationService: AuthenticationService) {
  return authenticationService;
}

@NgModule({
  imports: [AuthModule],
  providers: [
    TokenService,
    AuthenticationService,
    { provide: PROTECTED_FALLBACK_PAGE_URI, useValue: '/' },
    { provide: PUBLIC_FALLBACK_PAGE_URI, useValue: '/login' },
    {
      provide: AUTH_SERVICE,
      deps: [AuthenticationService],
      useFactory: factory
    }
  ]
})
export class AuthenticationModule {

}

Your help will be appreciate it.

serhiisol commented 6 years ago

Hi @nimatullah, have you seen this repo https://github.com/serhiisol/ngx-auth-example with example? It has everything for this case

nimatrazmjo commented 6 years ago

My mistake, I change my refresh routes but didn't change the verifyTokenRequest