Interceptor issue in login and logout in angular 8 - node.js

In my angular application i have used login and logout concept by MEAN(mongo,Express,Angular,Node).
After login within few min if i reload the page automatically going to login page.Token is there but it is redirecting to login page.I do not know why it is happening like this.Below given my code.
auth.guard.ts:
import { Injectable } from '#angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from
'#angular/router';
import { Observable } from 'rxjs';
import { UserService } from "../shared/user.service";
import { Router } from "#angular/router";
#Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private userService : UserService,private router : Router){}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean {
if (!this.userService.isLoggedIn()) {
this.router.navigateByUrl('/login');
this.userService.deleteToken();
return false;
}
return true;
}
}
user.service.ts:
getToken() {
return localStorage.getItem('usertoken');
}
setToken(token: string) {
localStorage.setItem('token', token);
}
getToken() {
return localStorage.getItem('token');
}
deleteToken() {
localStorage.removeItem('token');
}
getUserPayload() {
var token = this.getToken();
if (token) {
var userPayload = atob(token.split('.')[1]);
return JSON.parse(userPayload);
}
else
return null;
}
isLoggedIn() {
var userPayload = this.getUserPayload();
if (userPayload)
return userPayload.exp > Date.now() / 1000;
else
return false;
}
After logged within 2 or 3 min if i refresh the page getting err.error.auth is false.Why it is happening like this?
auth.intercepter.ts:
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from "#angular/common/http";
import { Injectable } from '#angular/core';
import { tap } from 'rxjs/operators';
import { Router } from "#angular/router";
import { UserService } from "../shared/user.service";
#Injectable()
export class UserAuthInterceptor implements HttpInterceptor {
constructor(private userService : UserService,private router : Router){}
intercept(req: HttpRequest<any>, next: HttpHandler) {
if (req.headers.get('noauth'))
return next.handle(req.clone());
else {
const clonedreq = req.clone({
headers: req.headers.set("Authorization", "Bearer " + this.userService.getToken())
});
return next.handle(clonedreq).pipe(
tap(
event => { },
err => {
if (err.error.auth == false) {
this.router.navigateByUrl('/login'); //After login within 2 or 3 min if i refresh or reload the page this is working.I do not know why this is calling on reload the page
}
})
);
}
}
}

Related

How to fix unknown authentication strategy "jwt" when I inject another service into user service in nestjs

I have a user service that handles registration, login and some other functions. I have been working on the application for sometime now with over 10 modules. But I noticed each time I injected another service and I try to consume any endpoint I get this error "Unknown authentication strategy "jwt". Error on swagger is:-
Internal Server Error
Response body
{
"statusCode": 500,
"message": "Internal server error"
}
Once I remove the injected service from the user module, everything is fine again. I have been trying to fix this because I need to use this service inside the user module.
This is the jwt.Strategy.ts
import { Injectable, HttpException, HttpStatus } from "#nestjs/common";
import { PassportStrategy } from '#nestjs/passport';
import { Strategy, ExtractJwt, VerifiedCallback } from "passport-jwt";
import { AuthService } from './auth.service';
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: process.env.SECRETKEY
});
}
async validate(payload: any, done: VerifiedCallback) {
const user = await this.authService.validateUser(payload);
try {
if (user) {
//return user;
return done(null, user, payload.iat)
} else if (user == null) {
const Terminal = await this.authService.validatePos(payload);
return done(null, Terminal, payload.iat)
}
else {
return done(
//throw new UnauthorizedException();
new HttpException('Unauthorised access', HttpStatus.UNAUTHORIZED),
false,
);
}
} catch (error) {
return error;
}
}
}
This is the AuthModule
import { Module } from '#nestjs/common';
import { AuthService } from './auth.service';
import { UserService } from '../user/user.service';
import { UserSchema } from '../user/user.schema';
import { MongooseModule } from '#nestjs/mongoose';
import { JwtStrategy } from './jwt.strategy';
import { ActivityLogService } from '../activity-log/activity-log.service';
import { ApiKeyStrategy } from './apiKey.strategy';
import { PassportModule } from "#nestjs/passport";
#Module({
imports: [MongooseModule.forFeature([{ name: 'User', schema: UserSchema }]),
PassportModule.register({
secret: "mysec"
}),
ActivityLogService],
providers: [AuthService, UserService, JwtStrategy, ApiKeyStrategy, ActivityLogService],
exports: [AuthService],
controllers: []
})
export class AuthModule { }
This is the api.strategy.ts
import { HeaderAPIKeyStrategy } from 'passport-headerapikey';
import { PassportStrategy } from '#nestjs/passport';
import { Injectable, HttpException, HttpStatus } from '#nestjs/common';
import { AuthService } from './auth.service';
#Injectable()
export class ApiKeyStrategy extends PassportStrategy(HeaderAPIKeyStrategy) {
constructor(private authService: AuthService) {
super({
header: 'api_key',
prefix: ''
}, true,
(apikey: string, done: any, req: any, next: () => void) => {
const checkKey = this.authService.validateApiKey(apikey);
if (!checkKey) {
return done(
new HttpException('Unauthorized access, verify the token is correct', HttpStatus.UNAUTHORIZED),
false,
);
}
return done(null, true, next);
});
}
}
This is the authService
import { Injectable } from '#nestjs/common';
import { sign } from 'jsonwebtoken';
import { UserService } from '../user/user.service';
import { TerminalService } from '../terminal/terminal.service';
import { InjectModel } from '#nestjs/mongoose';
import { Model } from 'mongoose';
import { Terminal } from '../terminal/interfaces/terminal.interface';
#Injectable()
export class AuthService {
constructor(private userService: UserService, #InjectModel('Terminal') private terminalModel: Model<Terminal>,) { }
//generate token for user
async signPayLoad(payload: any) {
return sign(payload, process.env.SECRETKEY, { expiresIn: '1h' });
}
//find user with payload
async validateUser(payload: any) {
const returnuser = await this.userService.findByPayLoad(payload);
return returnuser;
}
//generate token for Posy
async signPosPayLoad(payload: any) {
return sign(payload, process.env.SECRETKEY, { expiresIn: '24h' });
}
//find terminal with payload
async validatePos(payload: any) {
const { terminalId } = payload;
const terminal = await this.terminalModel.findById(terminalId);
return terminal;
}
validateApiKey(apiKey: string) {
const keys = process.env.API_KEYS;
const apiKeys = keys.split(',');
return apiKeys.find(key => apiKey === key);
}
}
This is the user service
import { Injectable, HttpException, HttpStatus, Inject } from '#nestjs/common';
import { User } from './interfaces/user.interface';
import { Model } from 'mongoose';
import { InjectModel } from '#nestjs/mongoose';
import { LoginUserDto } from './login-user.dto';
import { ActivityLogService } from '../activity-log/activity-log.service';
import { UpdateUserDTO } from './dtos/update_user.dto';
#Injectable()
export class UserService {
constructor(#InjectModel('User') private userModel: Model<User>,
private activityLogService: ActivityLogService,
) { }
//Login user
private users = [
{
"userId": 1,
"name": "John Doe",
"username": "john",
"password": "john123"
},
]
async login(loginDTO: LoginUserDto) {
const { email, password } = loginDTO;
return await this.users.find(users => users.username == email)
}
async findByPayLoad(payload: any) {
const { userId } = payload;
return await this.userModel.findById(userId)
}
async getAllUser() {
return this.users;
}
}
I cant figure out what I am doing wrong
Besides the code being difficult to manipulate and determine what's happening, services being in places they shouldn't and re-instantiations of services all over the place, the culprit as to why you are getting the error is simply because you never register the PassportModule from #nestjs/passport
EDIT 1/7/2017
Coming back to this answer about a year and a half later, it looks like the real issue is the use of a REQUEST scoped provider in the strategy. The nest docs explicitly mention this can't be done directly but also have a workaround for it.

TypeError: token.split is not a function

I Have get some error while login which is not expected but i try to solve it from 2 days but i cannot. I am using Nodejs for the api and angular 7 for the frontend
i have posted some of the code with the error
please help me to solve this
THANK YOU SO MUCH IN ADVANCE
auth.service.ts
import { Injectable } from "#angular/core";
import { Observable } from "rxjs";
import "rxjs/Rx";
import { JwtHelperService } from "#auth0/angular-jwt";
import "core-js/es7/reflect";
import { HttpClient } from "#angular/common/http";
const jwt = new JwtHelperService();
#Injectable()
export class AuthService {
private decodedToken;
constructor(private http: HttpClient) {}
public register(userData: any): Observable<any> {
return this.http.post("/api/v1/users/register", userData);
}
public login(userData: any): Observable<any> {
return this.http.post("/api/v1/users/auth", userData).map(token => {
//debugger;
return this.saveToken(token);
});
}
private saveToken(token): string {
//debugger;
this.decodedToken = jwt.decodeToken(token);
localStorage.setItem("bwm_auth", token.token);
localStorage.setItem("bwm_meta", JSON.stringify(this.decodedToken));
return token;
}
}
login.component.ts
import { Component, OnInit } from "#angular/core";
import { Router, ActivatedRoute } from "#angular/router";
import { AuthService } from "../shared/auth.service";
import { FormBuilder, FormGroup, Validators } from "#angular/forms";
#Component({
selector: "bwm-login",
templateUrl: "./login.component.html",
styleUrls: ["./login.component.scss"]
})
export class LoginComponent implements OnInit {
loginForm: FormGroup;
mistake: any[] = [];
notifyMessage: string = "";
constructor(
private fb: FormBuilder,
private auth: AuthService,
private router: Router,
private route: ActivatedRoute
) {}
ngOnInit() {
this.initForm();
this.route.params.subscribe(params => {
if (params["registered"] == "success") {
//debugger;
this.notifyMessage =
"You have been successfully registered you can login now";
}
});
}
initForm() {
this.loginForm = this.fb.group({
email: [
"",
[
Validators.required,
Validators.pattern(
"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+#[a-zA-Z0-9-]+(?:.[a-zA-Z0-9-]+)*$"
)
]
],
password: ["", Validators.required]
});
}
isInvalidForm(fieldName): boolean {
return (
this.loginForm.controls[fieldName].invalid &&
(this.loginForm.controls[fieldName].dirty ||
this.loginForm.controls[fieldName].touched)
);
}
isRequiredForm(fieldName): boolean {
return this.loginForm.controls[fieldName].errors.required;
}
login() {
// debugger;
//console.log(this.loginForm.value);
this.auth.login(this.loginForm.value).subscribe(
token => {
//debugger;
this.router.navigate(["/rentals"]);
},
errorResponse => {
// debugger;
console.log(errorResponse);
// this.mistake = errorResponse.error.errors;
//this.mistake = errorResponse.error;
}
);
}
}
error in browser
TypeError: token.split is not a function
at JwtHelperService.push../node_modules/#auth0/angular-jwt/src/jwthelper.service.js.JwtHelperService.decodeToken (jwthelper.service.js:70)
at AuthService.push../src/app/auth/shared/auth.service.ts.AuthService.saveToken (auth.service.ts:26)
at MapSubscriber.project (auth.service.ts:20)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next (map.js:35)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next (map.js:41)
at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
at FilterSubscriber.push../node_modules/rxjs/_esm5/internal/operators/filter.js.FilterSubscriber._next (filter.js:38)
at FilterSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
at MergeMapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/mergeMap.js.MergeMapSubscriber.notifyNext (mergeMap.js:84)
error in browser
As it seems the token that is returned from server is not string type
public login(userData: any): Observable<any> {
return this.http.post("/api/v1/users/auth", userData).map(token => {
//debugger;
return this.saveToken(token);
});
}
try to check it what is returned from server

How to implement SSO using an angular 6+ nodejs

I want to implement Single sign-on, but I don't quite understand how to do it. That's what I have at the moment. In fact, I have no mistakes. It's just that Single Sign-on is not working, in both clients I have to log in both times, although the server is one. I use Angular 6 nodejs (express)
token.interceptor.ts:
import { Injectable } from "#angular/core";
import { AuthService } from "../services/auth.service";
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from "#angular/common/http";
import { Observable, throwError } from "rxjs";
import { catchError } from "rxjs/operators";
import { Router } from "#angular/router";
#Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(private auth: AuthService, private router: Router){
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (this.auth.isAuthenticated()) {
req = req.clone({
setHeaders: {
Authorization: this.auth.getToken()
}
})
}
return next.handle(req).pipe(
catchError(
(error: HttpErrorResponse) => this.handleAuthError(error)
)
)
}
private handleAuthError(error: HttpErrorResponse): Observable<any> {
if (error.status === 401) {
this.router.navigate(['/login']), {
queryParams: {
sessionFailed: true
}
}
}
return throwError(error)
}
}
app.component.ts:
import { Component, OnInit } from '#angular/core';
import { AuthService } from './shared/services/auth.service';
#Component({
selector: 'app-root',
template: '<router-outlet></router-outlet>'
})
export class AppComponent implements OnInit {
constructor(private auth: AuthService) {}
ngOnInit() {
const potentialToken = localStorage.getItem('auth-token')
if (potentialToken !== null) {
this.auth.setToken(potentialToken)
}
}
}
authService:
import { Injectable } from "#angular/core";
import { HttpClient } from "#angular/common/http";
import { Observable } from "rxjs";
import { tap } from "rxjs/operators";
import { User } from "../interfaces";
#Injectable({
providedIn: 'root'
})
export class AuthService {
private token = null;
constructor(private http: HttpClient) {
}
login(user: User): Observable<{token: string}> {
return this.http.post<{token: string}>('/api/auth/login', user)
.pipe(
tap(
({token}) => {
localStorage.setItem('auth-token', token)
this.setToken(token)
}
)
)
}
setToken(token: string) {
this.token = token
}
getToken(): string {
return this.token
}
isAuthenticated(): boolean {
return !!this.token
}
logout() {
this.setToken(null)
localStorage.clear()
}
}

How to implement a profile?

I have a token based authorization. Authorization happens well there are no errors. But now need to somehow display the data of an authorized user. Please tell me how to properly implement the profile on the client (Angular 6)?
I have this server:
controller:
const db = require('../config/db.config.js')
const User = db.user
const errorHandler = require('../utils/errorHandler')
module.exports.getProfile = async function(req, res) {
try {
await User.findOne({ id: req.user.id}, (user) => {
res.json({
success: true,
user: user,
message: "Successful"
})
})
}catch(e) {
errorHandler(req, e)
}
}
routes:
const express = require('express')
const router = express.Router()
const controller = require('../controllers/user')
const passport = require('passport')
router.get('/profile', passport.authenticate('jwt', {session: false}), controller.getProfile)
module.exports = router
passport:
const JwtStrategy = require('passport-jwt').Strategy
const ExtractJwt = require('passport-jwt').ExtractJwt
const db = require('../config/db.config.js')
const User = db.user
const options = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.SECRET_OR_KEY
}
module.exports = passport => {
passport.use(
new JwtStrategy(options, async (payload, done) => {
try {
const user = await User.findById(payload.userId).toJSON('username id')
if (user) {
done(null, user)
} else {
done(null, false)
}
} catch(e) {
console.log(e)
}
})
)
}
And here is a part of the client:
app-components:
import { Component, OnInit } from '#angular/core';
import { AuthService } from './shared/services/auth.service';
#Component({
selector: 'app-root',
template: '<router-outlet></router-outlet>'
})
export class AppComponent implements OnInit {
constructor(private auth: AuthService) {
}
ngOnInit() {
const potentialToken = localStorage.getItem('auth-token')
if (potentialToken !== null) {
this.auth.setToken(potentialToken)
}
}
}
auth.service:
import { Injectable, Optional } from "#angular/core";
import { HttpClient } from "#angular/common/http";
import { Router, ActivatedRoute } from "#angular/router";
import { Observable } from "rxjs";
import { tap } from "rxjs/operators";
import { User } from "../interfaces";
#Injectable({
providedIn: 'root'
})
export class AuthService {
private token = null;
constructor(
private http: HttpClient,
#Optional() private _activatedRoute: ActivatedRoute,
#Optional() private _router: Router
) {}
login(user: User): Observable<{token: string}> {
return this.http.post<{token: string}>('/api/auth/login', user)
.pipe(
tap(
({token}) => {
localStorage.setItem('auth-token', token)
this.setToken(token)
}
)
)
}
setToken(token: string) {
this.token = token
}
getToken(): string {
return this.token
}
isAuthenticated(): boolean {
return !!this.token
}
logout() {
this.setToken(null)
localStorage.clear()
}
}
token.interceptor.ts:
import { Injectable } from "#angular/core";
import { AuthService } from "../services/auth.service";
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from "#angular/common/http";
import { Observable, throwError } from "rxjs";
import { catchError } from "rxjs/operators";
import { Router } from "#angular/router";
#Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(private auth: AuthService, private router: Router){
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (this.auth.isAuthenticated()) {
req = req.clone({
setHeaders: {
Authorization: this.auth.getToken()
}
})
}
return next.handle(req).pipe(
catchError(
(error: HttpErrorResponse) => this.handleAuthError(error)
)
)
}
private handleAuthError(error: HttpErrorResponse): Observable<any> {
if (error.status === 401) {
this.router.navigate(['/sign_in']), {
queryParams: {
sessionFailed: true
}
}
}
return throwError(error)
}
}
What need to implement on the client to display user data. Tell me please, I'm new.
You just need to create a Service class called UserService which will keep the information related to logged in user.
Whenever login action is performed successfully, just get the user details and fill it in UserService class.
user.service.ts
export class UserService {
private currentUser$: new BehaviorSubject<User>; //<-- check your user type
constructor(private http: Http) { }
getCurrentUser() {
this.currentUser$;
}
setCurrentUser(user:User){
this.currentUser$.next(user); //update the current user
}
}
This service class will give the Observable and you can use it any component or service class.

Angular 5 - Cannot use response from GET request

I've been at this and looking for a solution for two days now. Hoping someone can help me. I'm new to Angular 5.
I'm trying to utilize the WP REST API for a front page application. After following this tutorial:
http://techattitude.com/tips-tricks-and-hacks/how-to-remotely-create-a-user-on-your-wordpress-website-using-json-api-request/
I found that the there is a response that comes through, but I cannot access the response. I'm trying to console.log() the response value and nothing is appearing. Here is my code below, please have a look and let me know what I'm doing wrong. I have implemented my GET request through a service.
api-config-nonce.ts
export interface ApiConfigNonce {
status: String,
controller: String,
method: String,
nonce: String
}
auth.service.ts
import { EventEmitter, Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { ModalService } from '../services/modal.service';
import { Observable } from 'rxjs/Observable';
import { map } from 'rxjs/operators';
import { ApiConfigNonce } from '../api-config-nonce';
#Injectable()
export class AuthService {
apiHost:string = 'http://localhost/';
apiBase:string = 'b0ffv3BH7K6h/';
email:string;
password:string;
userSignIn = new EventEmitter<object>();
constructor(private http:HttpClient, private modalService:
ModalService){
}
login(email, password){
console.log('login()');
let options = {
"insecure":"cool",
"email":email,
"password": password
}
return this.http.post(this.apiHost + this.apiBase +
'user/generate_auth_cookie/' , options);
}
getNonce(){
return this.http.get<ApiConfigNonce>(this.apiHost + this.apiBase +
'get_nonce/?controller=user&method=register')
.map(res => res);
}
newUser(username, email, password, firstname, lastname, nonce){
return this.http.get(this.apiHost + this.apiBase + 'user/register/?
username='+ username + '&email=' + email + '&nonce=' + nonce +
'&first_name=' + firstname + '&last_name=' + lastname);
}
}
sign-up.component.ts
import { Component, OnInit, AfterViewInit, ViewChild } from
'#angular/core';
import { FormsModule } from '#angular/forms';
import { NgForm } from '#angular/forms';
import { UsersService } from '../../services/users.service';
import { AuthService } from '../../services/auth.service';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-sign-up',
templateUrl: './sign-up.component.html',
styleUrls: ['./sign-up.component.scss']
})
export class SignUpComponent implements OnInit, AfterViewInit {
#ViewChild('f') signupForm: NgForm;
signUpDetails:object;
busyProcessing:boolean = false;
errorMessage:string = null;
token:string = null;
userId:number = null;
nonce:any;
constructor(private usersService: UsersService, private authService:
AuthService, private http:HttpClient) { }
ngOnInit() {
this.getNonce();
}
ngAfterViewInit(){
}
getNonce(){
console.log('getNonce()');
this.authService.getNonce()
.subscribe(
data => {
this.nonce = JSON.stringify(data);
console.log(data);
},
(error)=>{
this.onError(error);
console.log(error);
}
);
console.log(this.nonce);
}
onError(response){
switch (response.error.code) {
case 406:
this.errorMessage = "Either that email or username is already in
use";
break;
case 403:
this.errorMessage = "Failed to authorize, please try again later";
default:
this.errorMessage = "There was an error signing you up, please try
again";
break;
}
this.busyProcessing = false;
}
}
The function in my component that is utilizing my service is getNonce(). I'm not sure why when I test the endpoints on postman I can see the response but cannot assign that response to a variable to use it. It renders this error:
"Http failure response for (unknown url): 0 Unknown Error"
Any help would be very appreciated.

Resources