GET Request 401 (Unauthorized) - node.js

In Postman the profile is authorized and a json object is returned.
But on the front-end, I'm getting this error.
HttpErrorResponse {headers: HttpHeaders, status: 401, statusText: "Unauthorized", url: "http://localhost:3000/users/profile", ok: false, …}
Here is my auth.service.ts file:
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Observable, Subject } from 'rxjs';
import 'rxjs/add/operator/map';
interface data{
success: boolean;
msg: string;
token: string;
user: any;
}
export class AuthService {
authToken: any;
user: any;
constructor(private http: HttpClient) { }
getProfile() {
let headers = new HttpHeaders();
this.loadToken();
headers.append('Authorization', this.authToken);
headers.append('Content-Type', 'application/json');
return this.http.get<data>('http://localhost:3000/users/profile', {headers: headers})
.map(res => res);
}
loadToken(){
const Token = localStorage.getItem('id_token');
this.authToken = Token;
}
}
profile.ts file:
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../../services/auth.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
user: Object;
constructor(
private authService: AuthService,
private router: Router,
) { }
ngOnInit() {
this.authService.getProfile().subscribe(profile => {
this.user = profile.user;
},
err => {
console.log(err);
return false;
});
}
}

this is happening because this.loadToken() returns you the token. you have to wait till you this.loadToken() function returns you the authToken.
for this, you can use async and await for your function or else just return the value from this.loadToken like
getProfile() {
let headers = new HttpHeaders();
this.authToken = this.loadToken();
headers.append('Authorization', this.authToken);
headers.append('Content-Type', 'application/json');
return this.http.get<data>('http://localhost:3000/users/profile', {headers: headers})
.map(res => res);
}
loadToken(){
const Token = localStorage.getItem('id_token');
return Token;
}

Not sure this will help but try to enable CORS in your WebAPI project:
WebApiConfig.cs (Register Method):
EnableCorsAttribute cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);

Related

Nestjs HttpService error handling with AxiosRequestConfig's validateStatus function

I need to handle http errors status code (such as 401, 500, etc) which can occur when consuming an external service using HttpService (HttpModule of Nestjs). Here is the implementation i am working on:
import { Injectable } from '#nestjs/common';
import { HttpService } from '#nestjs/axios';
import { Logger } from '#nestjs/common';
import { AxiosRequestConfig } from 'axios';
import { catchError, firstValueFrom, map } from 'rxjs';
type Person = {
name: string;
lastName: string;
};
#Injectable()
export class PersonService {
constructor(private httpService: HttpService) {}
async findPerson(): Promise<Person> {
const axiosConfig: AxiosRequestConfig = {
method: 'get',
url: 'https://service.dns/path/person',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${jwt}`,
},
validateStatus: function (status: number) {
return status === 200;
},
};
const personInstance: Person = await firstValueFrom(
this.httpService.request(axiosConfig).pipe(
catchError((e) => {
Logger.error(e.response.data.errorMessage);
throw new Error('internal communication error');
}),
map((res) => {
return res.data;
}),
),
);
return personInstance;
}
}
In the code above, I just need the function catchError throws the custom error, but I am not able to make the function validateStatus to trigger the execution of catchError.
I have implemented next code in order to take advantage of validateStatus function of AxiosRequestConfig for giving solution to my needs:
import { Injectable } from '#nestjs/common';
import { HttpService } from '#nestjs/axios';
import { Logger } from '#nestjs/common';
import { AxiosRequestConfig } from 'axios';
import { firstValueFrom } from 'rxjs';
type Person = {
name: string;
lastName: string;
};
#Injectable()
export class PersonService {
constructor(private httpService: HttpService) {}
async findPerson(): Promise<Person> {
const axiosConfig: AxiosRequestConfig = {
method: 'get',
url: 'https://service.dns/path/person',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer fake_jwt`,
},
validateStatus: function (status: number) {
return status === 200;
},
};
return firstValueFrom(this.httpService.request(axiosConfig))
.then((res) => res.data)
.catch((e) => {
Logger.error(e.errorMessage);
throw new Error('internal communication error');
});
}
}
Note: this code deals with Promise<AxiosResponse<any>> instead of Observable<AxiosResponse<any> methods

Property 'success' does not exist on type 'Object'

user.js
router.post('/register', (req, res) => {
let newUser = new User({
name: req.body.name,
email: req.body.email,
username: req.body.username,
password: req.body.password
});
User.addUser(newUser, (err, user) => {
if (err) {
res.json({ "success": false, msg: 'Failed to register User' })
} else {
res.json({ "success": true, msg: "User Added" })
}
})
});
authservice.ts
import { catchError,map } from 'rxjs/operators';
import { Injectable } from '#angular/core';
import {HttpClient,HttpHeaders,HttpErrorResponse} from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class AuthService {
constructor(private http:HttpClient) { }
registerUser(user){
let headers = new HttpHeaders();
headers.append('content-type','application/json');
return this.http.post('http://localhost:8080/users/register',user,
{headers:headers})
}
}
register.component.ts
import { ValidateService } from './../../services/validate.service';
import { Component, OnInit } from '#angular/core';
import { FlashMessagesService } from 'angular2-flash-messages';
import {AuthService} from '../../services/auth/auth.service';
import {Router } from '#angular/router';
#Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.css']
})
export class RegisterComponent implements OnInit {
name:String;
username:String;
email:String;
password:String;
constructor(private _validate:ValidateService,
private _flashMessagesService: FlashMessagesService,
private _authservice:AuthService,
private _router:Router) { }
ngOnInit() {
}
onRegisterSubmit(){
const user={
name:this.name,
username:this.username,
email:this.email,
password:this.password,
}
this._authservice.registerUser(user)
.subscribe(data =>{
console.log(data);
**if(data.success){**
this._flashMessagesService.show('Registration Succesfull ! ',{cssClass:'alert-success',timeout:3000})
this._router.navigate(['/login']);
}else{
this._flashMessagesService.show('Oops Something went wrong! ',{cssClass:'alert-danger',timeout:3000})
this._router.navigate(['/register'])
}
})
}
}
Error
ERROR in src/app/components/register/register.component.ts(49,17): error TS2339: Property 'success' does not exist on type 'Object'.
The data is submitting succesfully and even the angular is redirecting succesfully to the next component but this is giving error. in register.component.ts while subscribing the property success of the returned object in if statement if(data.success)
You can using code below:
dataRegister:any={}
//Function register
this._authservice.registerUser(user)
.subscribe(data =>{
this.dataRegister = data;
if(this.dataRegister.success){
//
}
else{
//
}
}
You can use type checking on your responses to avoid such errors.
Create a RegisterResponse class that will contain the structure of your HTTP response.
export class RegisterResponse {
public success: boolean;
public msg: string;
}
Then pass it to your http.post() method as generic parameter:
import { RegisterResponse } from './RegisterResponse'; // Or wherever it is..
export class AuthService {
constructor(private http:HttpClient) { }
registerUser(user){
let headers = new HttpHeaders();
headers.append('content-type','application/json');
return this.http.post<RegisterResponse>('http://localhost:8080/users/register', user, {headers:headers});
}
}
The registerUser() method will return you an Observable<RegisterResponse> type, so when you subscribe to it, you data variables will be of type RegisterResponse. But you can also specify the type if you want:
this._authservice.registerUser(user)
.subscribe((data: RegisterResponse) => {
if (data.success) {
// ...
}
else {
// ...
}
});
Hope it helps.

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 6 not getting response from expressjs node server

help a noob out, I am building a MEAN stack app and i ran into a problem where I cannot read a response from the express server but the response is generated when I use postman, here is my code
auth.service.ts
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import { map } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class AuthService {
authToken: any;
user: any;
constructor(private http:Http) { }
registerUser(user){
let headers = new Headers();
headers.append('Content-Type','application/json');
return this.http.post('http://localhost:3000/users/register',user,
{headers: headers})
.pipe(map(res => res.json));
}
authenticateUser(user){
let headers = new Headers();
headers.append('Content-Type','application/json');
return this.http.post('http://localhost:3000/users/authenticate',user,
{headers: headers})
.pipe(map(res => res.json));
}
}
login.component.ts
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../../services/auth.service';
import { Router } from '#angular/router';
import { FlashMessagesService } from 'angular2-flash-messages';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
username: String;
password: String;
constructor(private authService: AuthService,
private router: Router,
private flashMessage: FlashMessagesService
) { }
ngOnInit() {
}
onLoginSubmit(){
const user = {
username: this.username,
password: this.password
}
this.authService.authenticateUser(user).subscribe(data => {
console.log(data);
});
}
}
Chrome Console
ƒ () { login.component.ts:29
if (typeof this._body === 'string') {
return JSON.parse(this._body);
}
if (this._body instanceof ArrayBuffer) {
return JSON.parse(this.text());
Below is the response in Postman :
The error is in your pipe function.
pipe(map( res => res.json ))
You need to call res.json() inside your map. Convert it to
pipe(map( res => res.json() ))
However, converting the response to JSON is not required over Angular v5.
Correct code is as below:-
authenticateUser(user){
let headers = new Headers();
headers.append('Content-Type','application/json');
return this.http.post('http://localhost:3000/users/authenticate',user,
{headers: headers})
.pipe(map(res => res.json()));
}
Looks like data coming from authenticateUser is a function. Have you tried calling it?

Unauthorized 401 error GET http://localhost:3000/users/profile 401 (Unauthorized)

I was trying to get user information on profile page but it is showing GET http://localhost:3000/users/profile 401 (Unauthorized).
Please find the image on below link which i getting.
enter image description here
Here the code which i using in three files.
This is auth.service.ts
import { Injectable } from '#angular/core';
import {Http, Headers} from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class AuthService {
authToken: any;
user: any;
constructor(private http:Http) { }
registerUser(user){
let headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.post('http://localhost:3000/users/register', user,{headers: headers})
.map(res => res.json());
}
authenticateUser(user){
let headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.post('http://localhost:3000/users/authenticate', user,{headers: headers})
.map(res => res.json());
}
getProfile(){
let headers = new Headers();
this.loadToken();
headers.append('Autherization', this.authToken);
headers.append('Content-Type', 'application/json');
return this.http.get('http://localhost:3000/users/profile',{headers: headers})
.map(res => res.json());
}
storeUserData(token, user){
localStorage.setItem('id_token', token);
localStorage.setItem('user', JSON.stringify(user));
this.authToken = token;
this.user = user;
}
loadToken(){
const token = localStorage.getItem('id_token');
this.authToken = token;
}
logout(){
this.authToken = null;
this.user = null;
localStorage.clear();
}
}
This is profile.component.ts
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../../services/auth.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
user: Object;
constructor(
private authService : AuthService,
private router: Router
) { }
ngOnInit() {
this.authService.getProfile().subscribe(profile => {
this.user = profile.user;
},
err => {
console.log(err);
return false;
});
}
}
This is profile.component.html
<div *ngIf="user">
<h2 class="page-header" >{{user.name}}</h2>
<ul class="list-group">
<li class="list-group-item">Username: {{user.username}}</li>
<li class="list-group-item">Email: {{user.email}}</li>
</ul>
</div>
I got output, there was small spelling mistake in authorization. now it is working.
In getProfile function which is in auth.service.ts make these changes :
`getProfile(){
let headers = new Headers();
this.loadToken();
headers.append('Authorization', this.authToken);
headers.append('Content-Type', 'application/json');
return this.http.get('http://localhost:3000/users/profile',{headers:
headers})
map(res => res.json());
}`
Just change Autherization to Authorization
Hope it helps
Try it
getProfile(){
let headers = new Headers();
this.loadToken();
headers = headers.append('Autherization', this.authToken);
header = headers.append('Content-Type', 'application/json');
return this.http.get('http://localhost:3000/users/profile',{headers: headers})
.map(res => res.json()); }

Resources