I have created login form with angular 8 and node js. I have set the session using node js in back end. i couldnt check session set or not in angular for avoid access dashboard without logged in. Kindly suggest the way to use login system using angular 8 and node js. Thanks.....
A very popular method is to use JWT (JSON Web Tokens) npm package to authenticate.
The process would be:
Send credentials to the server
Server generates and sends back JWT or a Bearer Token
FrontEnd would store it in browser cookies or localStorage
localStorage.setItem('TOKEN', tokenReceivedFromServer);
In subsequent Api Calls the token would be sent to the server in a Header (Authorization).
Authorization: `JWT ${localStorage.getItem('TOKEN')}`
FYI: JWT keyword is removed from string on the server before parsing token
The frontend can check if the token is set in storage to show login page / dashboard
First we need to check the login credentials valid or not in application.
In angular application component typescript file, we have send the data service in argument, the service send the values to backend using httpclient. If credentials valid we set the value in localstorage.
submitLogin(data:any)
{
this.LoginService.loginData(data).subscribe(data =>{
if(data.body.status_code == 404)
{
Swal.fire({
icon: 'warning',
title: 'Invalid E-Mail/Password!',
}).then(function(){
});
}else if(data.body.status_code ==200)
{
localStorage.setItem("user_id",data.body.token);
this.router.navigate(['/Dashboard']);
}else
{
Swal.fire({
icon: 'error',
title: 'Process Failed!',
}).then(function(){
});
}
});
}
In service.ts file make sure about those packages import
import { HttpClient } from '#angular/common/http';
import { Observable, throwError } from 'rxjs';
import {Login} from './login';
in loginData function
url = "http://localhost:3000/loginCheck";
loginData(Login:Login):Observable<any>
{
return this.http.post(this.url,Login,{observe: 'response'});
}
in backend i have used node.js
in file app.js
first install jsonwebtoken package and include in the file.
npm install jsonwebtoken
then set the jsonwebtoken when where condition satisfies
let payload = {subject:employee_id}
let token = jwt.sign(payload,'secretKey')
var response = {
'token': token,
"status_code":200,
}
res.send(response);
res.end();
Whenever we use the login in angular we must use the authguard routing its helps to access dashboard without logged in.
ng generate guard auth
in auth.guard.ts file we must include the package and service
import { CanActivate, Router } from '#angular/router';
import {LoginService} from './login.service';
export class AuthGuard implements CanActivate {
constructor(private LoginService:LoginService,private router:Router) {}
canActivate(): boolean
{
if(this.LoginService.loggedIn())
{
return true
}else
{
this.router.navigate(['/login']);
return false;
}
}
}
In this file we just checking the localstorage value set or not in boolean datatype.
in service file
add the following code for get and return in boolean type
loggedIn()
{
return !!localStorage.getItem('user_id')
}
getToken()
{
return localStorage.getItem('user_id')
}
if its returns true we can access the dasboard, else its redirected to login page.
We must use this canActive function in routing otherwise it will not working
In app-routing.module.ts file
import { AuthGuard } from './auth.guard';
const routes: Routes = [
{path:'Dashboard',component:DashboardComponent},
{path:'receipt',component:ReciptComponentComponent,canActivate:[AuthGuard]},
];
It will helpus to access dashboard without loggedin but we need to check the token valid or not in backend, we can do that using angular interceptors
we should create the new service with interceptors name
ng g service token-interceptor
In interceptor file we need to import the following
import { Injectable,Injector } from '#angular/core';
import { HttpInterceptor } from '#angular/common/http';
import { LoginService } from './login.service';
In interceptors services inject in different way compared to component.
export class TokenInterceptorService implements HttpInterceptor{
constructor(private Injector:Injector) { }
intercept(req:any,next:any)
{
let loginService = this.Injector.get(LoginService);
let tokenzedReq = req.clone({
setHeaders:
{
Authorization: `Bearer ${loginService.getToken()}`
}
});
return next.handle(tokenzedReq)
}
}
we need to create a function in interceptors with the name intercept, then we need to inject the service as per injector.
In backend we need to create the helper function to verify the jsonwebtoken
if the authorization not set we can send the response 401 not found and can redirected to login page
function verifyToken(req,res,next)
{
if(!req.headers.authorization)
{
return res.status(401).send('Unauthorized request');
}
var token = req.headers.authorization.split(' ')[1];
if(!token)
{
return res.status(401).send('Unauthorized request');
}
if(token === 'null')
{
return res.status(401).send('Unauthorized request');
}
//let payload = jwt.verify(token,'secretKey');
let payload = jwt.decode(token,'secretKey');
if(!payload)
{
return res.status(401).send('Unauthorized request');
}
req.userId = payload.subject;
next();
}
then we can use this middleware function wherever we need
for example
app.get('/dashboard',verifyToken,function(req,res){
let events = [];
res.json(events);
});
In dashboard component ts file
this.dashboardService.getData().subscribe(data=>this.dashboardData=data,
err=>{
if(err instanceof HttpErrorResponse)
{
if(err.status===401)
{
this.router.navigate(['/login']);
}
}
})
in dashboard service ts file
url = "http://localhost:3000/dashboard";
getData()
{
return this.http.get<any>(this.url);
}
in app.module.ts file
import { AuthGuard } from './auth.guard';
import { ReciptComponentComponent } from './recipt-component/recipt-component.component';
import { HttpClientModule, HTTP_INTERCEPTORS } from '#angular/common/http';
import { TokenInterceptorService } from './token-interceptor.service';
import { DashboardServiceService } from './dashboard-service.service';
in providers
providers: [AuthGuard,{provide:HTTP_INTERCEPTORS,useClass:TokenInterceptorService,multi:true},DashboardServiceService],
Related
So I have a stored a token in a file "scratch" inside the assets of angular. I would like to use it in SpotifyService ti finally be authenticated but I dont know how angular can search my file and use it as a token:
Node Js
if (typeof localStorage === "undefined" || localStorage === null) {
var LocalStorage = require('node-localstorage').LocalStorage;
localStorage = new LocalStorage('./src/assets/scratch');
}
...
app.get('/auth/spotify/callback',
passport.authenticate('spotify',{failureRedirect:'/auth/error'}),
function(req,res){
const monToken=localStorage.getItem('token');
res.redirect('/');
})
Angular
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Injectable } from '#angular/core';
import {} from 'rxjs';
import { JwtHelperService } from "#auth0/angular-jwt";
#Injectable({
providedIn: 'root'
})
export class SpotifyService {
constructor(private http:HttpClient,private jwt:JwtHelperService) {
}
isAuthenticated() : Boolean {
let token=localStorage.getItem('token');
return (token != null && !this.jwt.isTokenExpired(token));
}
setTokenHeader(){
let devant: HttpHeaders=new HttpHeaders();
//devant.append('Content-Type', 'application/json');
let authToken=localStorage.getItem('token');
devant.append('Authorization', `Bearer ${authToken}`);
return devant;
}
private header: HttpHeaders = this.setTokenHeader();
Basically, I don't know how can I use the file 'token' inside. If there's another method to store the token in the API please wirte it bellow
you are doing it all wrong...
why do you wanna store the token in nodejs local storage...?
you don't have to store it just verify the token is valid or not which is passed from the cliend who has saved it
I'm trying to create a login application that passes a JWT in the headers of another application.
I started from this application User authentication keycloak 2 adapted to my Kecloak installation and it works fine.
Now I need to create a component that call an external URL passing the authorization token
In this component
import React, { Component } from 'react';
class callUrl1 extends Component {
constructor(props) {
super(props);
this.state = { response: null };
}
authorizationHeader() {
if(!this.props.keycloak) return {};
return {
headers: {
"Authorization": "Bearer " + this.props.keycloak.token
}
};
}
handleClick = () => {
console.log("callUrl1 called")
}
}
export default callUrl1;
I need something that call an external URL; something like:
SOME_FUNCTION('https://www.h.net/users', this.authorizationHeader())
to put inside handleClick.
All that I tried gives compilation errors.
How can I go from "http://localhost:3000" to "https://www.h.net/users" passing the JWT?
The built in library for making requests in frontend JS is called Fetch. Here's an example of how you might do it in your case:
handleClick = () => {
fetch('https://www.h.net/users', this.authorizationHeader())
.then((response) => {
// do something with the response here...
});
}
or with async/await:
handleClick = async () => {
const response = await fetch('https://www.h.net/users', this.authorizationHeader());
// do something with response like:
const data = await response.json();
}
For more information on Fetch, check out mdn: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
I'm trying to get access to the jwt payload in a route that is protected by an AuthGuard.
I'm using passport-jwt and the token payload is the email of the user.
I could achieve this by runing the code bellow:
import {
Controller,
Headers,
Post,
UseGuards,
} from '#nestjs/common';
import { JwtService } from '#nestjs/jwt';
import { AuthGuard } from '#nestjs/passport';
#Post()
#UseGuards(AuthGuard())
async create(#Headers() headers: any) {
Logger.log(this.jwtService.decode(headers.authorization.split(' ')[1]));
}
I want to know if there's a better way to do it?
Your JwtStrategy has a validate method. Here you have access to the JwtPayload. The return value of this method will be attached to the request (by default under the property user). So you can return whatever you need from the payload here:
async validate(payload: JwtPayload) {
// You can fetch additional information if needed
const user = await this.userService.findUser(payload);
if (!user) {
throw new UnauthorizedException();
}
return {user, email: payload.email};
}
And then access it in you controller by injecting the request:
#Post()
#UseGuards(AuthGuard())
async create(#Req() request) {
Logger.log(req.user.email);
}
You can make this more convenient by creating a custom decorator:
import { createParamDecorator } from '#nestjs/common';
export const User = createParamDecorator((data, req) => {
return req.user;
});
and then inject #User instead of #Req.
I am trying to figure out this scenario for my JWT based authentication in Apollo based graphql server (2.0) .
Basically after login a user gets accessToken and refreshToken from server.
AccessToken gets expired after certain period of time and server sends an error message indicating that token expired (TokenExpiredError) and then client need to communicate with server for new accessToken via passing refreshToken.
Flow is as following -
TokenExpiredError occurs
Get that error on client side
Queue all requests with old accessToken(so that server is not flooded with too many refreshToken calls and many accessTokens are generated by server)
Call refreshToken api on graphql server to get new accessToken
update accessToken for all authorised calls with new accessToken
Logout user incase refreshToken itself is expired
Prevent any kind of race condition b/w calls
I have already implemented refreshToken mutation on client side but can't figure out about when error occurs stop all requests -> request new token -> make all pending request again and if refresh token is expired logout user.
I followed this approach to solve my problem finally
Posting my approach for others
// #flow
import { ApolloLink, Observable } from 'apollo-link';
import type { ApolloClient } from 'apollo-client';
import type { Operation, NextLink } from 'apollo-link';
import { refreshToken2, getToken } from './token-service';
import { GraphQLError } from 'graphql';
export class AuthLink extends ApolloLink {
tokenRefreshingPromise: Promise<boolean> | null;
injectClient = (client: ApolloClient): void => {
this.client = client;
};
refreshToken = (): Promise<boolean> => {
//if (!this.tokenRefreshingPromise) this.tokenRefreshingPromise = refreshToken(this.client);
if (!this.tokenRefreshingPromise) this.tokenRefreshingPromise = refreshToken2();
return this.tokenRefreshingPromise;
};
setTokenHeader = (operation: Operation): void => {
const token = getToken();
if (token) operation.setContext({ headers: { authorization: `Bearer ${token}` } });
};
request(operation: Operation, forward: NextLink) {
// set token in header
this.setTokenHeader(operation);
// try refreshing token once if it has expired
return new Observable(observer => {
let subscription, innerSubscription, inner2Subscription;
try {
subscription = forward(operation).subscribe({
next: result => {
if (result.errors) {
console.log("---->", JSON.stringify(result.errors))
for (let err of result.errors) {
switch (err.extensions.code) {
case 'E140':
console.log('E140', result)
observer.error(result.errors)
break;
case 'G130':
this.refreshToken().then(response => {
if (response.data && !response.errors) {
this.setTokenHeader(operation);
innerSubscription = forward(operation).subscribe(observer);
} else {
console.log("After refresh token", JSON.stringify(response));
observer.next(response)
}
}).catch(console.log);
break;
}
}
}
observer.next(result)
},
complete: observer.complete.bind(observer),
error: netowrkError => {
observer.error(netowrkError);
}
},
});
} catch (e) {
observer.error(e);
}
return () => {
if (subscription) subscription.unsubscribe();
if (innerSubscription) innerSubscription.unsubscribe();
if (inner2Subscription) inner2Subscription.unsubscribe();
};
});
}
}
I am using nodejs, express, cookie-parser and angular 6. Right now angular runs in http://localhost:4200 and node/express in http://localhost:3000. I also put
const cors = require('cors');
app.use(cors());
in my app.js in node, so both angular and node can communicate.
In my login route I create an http-only cookie with the token and then I send back a JSON with some info and the user id
res.cookie("SESSIONID", token, {httpOnly:true, secure:true});
res.json({ success:true, msg:'you are logged in', userid: resolved.id});
I suppose that the SESSIONID cookie is send with every request back to the server , so I dont have to set it myself before every request
In my middleware, I want to get the token from the cookie in order to check it. So, I do
const token = req.cookies.SESSIONID;
console.log('token from validate : ', token);
//check token and expiration, either next(); or redirect back
in my routes I have
router.get('cms/account', myMiddleware.required(), (req, res)=>{
res.json({ msg:'profile data'});
});
My profile service contacts the account route of node
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import { map } from "rxjs/operators";
#Injectable({
providedIn: 'root'
})
export class ProfileService {
constructor(private http:Http) { }
getProfile(){
return this.http.get('http://localhost:3000/cms/account').pipe(map(res => res.json()));
}
}
my profile service should render some profile data
import { Component, OnInit } from '#angular/core';
import { ProfileService } from '../../services/profile.service';
#Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
constructor( private profileService: ProfileService) { }
ngOnInit() {
this.profileService.getProfile().subscribe((data) =>{
console.log('profileService -- ', data);
})
}
}
After I login I go to http://localhost:4200/cms/profile. In the console I see token from validate : undefined
So I am sure that angular successfully reaches until the validation middleware, but cannot get the cookie.
I fail to understand why the cookie is not there. Is it my synatx? Is it not set at the start? Should I include it with every request ? Is it the different ports in localhost ? I gave as much details I could, if you need extra, just tell me. Please help me debug this, because I am lost.
Thanks