How to move responses from service to controller? - nestjs

I have login service and login controller.
Service:
class LoginService {
private tokenService: TokenService;
constructor() {
this.tokenService = new TokenService();
this.login = this.login.bind(this);
this.getClient = this.getClient.bind(this);
this.getUserProfile = this.getUserProfile.bind(this);
}
public async login(req: Request, res: Response) {
try {
const { password } = req.body;
const client = await this.getClient(req, res);
const userProfile = await this.getUserProfile(client);
if (!comparePassword(password, userProfile.password))
return res.status(StatusCodes.UNAUTHORIZED).json({ error: 'Incorrect password' });
const tokens = this.tokenService.generateTokens(client);
this.tokenService.setToken(res, tokens);
return res.status(StatusCodes.OK).json(tokens);
} catch (error) {
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ msg: error.message });
}
}
}
Controller:
class LoginController {
private loginService: LoginService;
constructor(private router: IRouter) {
this.router = router;
this.loginService = new LoginService();
this.routes();
}
public routes() {
this.router.route('/auth').post(loginMiddleware, this.loginService.login);
}
}
So, my question is, how to move responses logic to controller correctly, cuz i'm just started to learn nestjs.

Related

Cannot GET /api/posts

post.controller.ts
class PostController implements Controller {
public path = '/posts';
public router = Router();
private PostService = new PostService();
constructor() {
this.initialiseRoutes();
}
private initialiseRoutes(): void {
this.router.get(
`${this.path}`, this.get);
}
private get = async (
req: Request,
res: Response,
next: NextFunction
): Promise<Response | void> => {
try {
const posts = await this.PostService.get();
res.status(200).json({ posts });
} catch (error:any) {
next(new HttpException(400, error.message));
}
};
}
export default PostController;
post.service.ts
class PostService {
private post = PostModel;
public async get(): Promise<Post[]> {
try {
const posts = await this.post.find();
return posts;
} catch (error) {
throw new Error('Unable to get posts');
}
}
}
export default PostService;
Trying out a Get request for a Blog Post Model in Nodejs+Express API with Mongodb. But getting "Cannot GET /api/posts" error. Other requests such as create posts and User CRUD actions are working fine.

TypeError: Cannot read properties of undefined (reading 'length') while using Interceptor

I have the following Angular and Node JS as follows
Interceptor
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from "#angular/common/http";
import { Injectable } from "#angular/core";
import { Observable } from "rxjs";
import { AuthService } from "../Services/auth.service";
#Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService : AuthService) {}
intercept(req: HttpRequest<any>, next: HttpHandler) {
//console.log(this.authService.getAuthToken())
const authToken = this.authService.getAuthToken();
const authRequest = req.clone({
headers: req.headers.set("Authorization", authToken)
});
console.log("authRequest");
return next.handle(authRequest);
}
}
service
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { api_url } from '../Models/global-url.model';
import { LoginModel } from '../Models/login_details.model';
import { ResponseFromServer } from '../Models/response.model';
#Injectable({
providedIn: 'root'
})
export class AuthService {
private token : string;
//Password is asish for all users
constructor(private http: HttpClient) { }
checkUserLogin(loginDetails: LoginModel) {
console.log(loginDetails);
this.http.post<{response: any}>(api_url+"login/loginUser", loginDetails).subscribe((result: ResponseFromServer) => {
console.log(result.token);
this.token = result.token;
console.log(this.token);
});
}
getAuthToken() {
return this.token;
}
}
User Defined Middleware in Node JS :-
const jwt = require('jsonwebtoken');
const s_token = require('../tokens/auth-token');
//const authFunction = (req, res, next) => {
module.exports = (req, res, next) => {
console.log(req);
var message = '';
try {
const token = req.headers.authorization;
console.log(token);
jwt.verify(token, s_token);
next();
} catch (err) {
message = "Auth Failed";
console.log(err); //JsonWebTokenError: Error jwt must be provided => user is not logged in
res.status(401).json(message);
// res.json(message); //Check the error message that occurs in browser console, while using this without status
}
}
login.js in Node Router :-
router.post('/loginUser', async (req, res, next) => {
const loginDetails = req.body;
console.log(loginDetails);
var { userId, stored_password,userEmailId,token,status_code } = '';
var message = '';
var response = '';
//console.log(loginDetails);
query = `SELECT * FROM tbl_users WHERE (tum_email = $1 OR tum_mobile = $1)`;
params = [loginDetails.username];
// await db.query(query, params, (err, result) => {
// if(err) {
// console.log(err);
// response = 'f0';
// message = "Internal Server Error. Please reload the page and try again.";
// } else if(result.rows.length) {
// //console.log(result.rows.length);
// userId = result.rows[0].tum_email;
// password = result.rows[0].tum_password;
// response = 's1';
// message = "";
// } else {
// response = 'f1';
// message = "User with the given user id does not exist. Please register here";
// }
// });
try {
const result = await db.query(query, params);
if(result.rowCount == 0 ) {
response = 'f1';
message = "User with the given user id does not exist. Please register here";
} else {
userId = result.rows[0].tum_id;
userEmailId = result.rows[0].tum_id;
stored_password = result.rows[0].tum_password;
try {
if ((await argon2.verify(stored_password, loginDetails.password))) {
//password matches
response = 'success';
const session_data = {
userId: userId,
email: userEmailId
}
token = jwt.sign(session_data, s_token, {expiresIn:'1hr'});
//console.log(token);
} else {
response = 'f2';
message = "Entered password is wrong. Please enter the correct password, or reset it";
}
} catch (err) {
console.log(err);
response = 'f0';
message = "Internal Server Error. Please reload the page and try again, or contact an Administrator";
}
}
} catch (err) {
console.log(err);
response = 'f0';
message = "Internal Server Error. Please reload the page and try again, or contact an Administrator";
}
const json_object = {
token: token,
response: response,
message:message
}
if(token != '') {
status_code = 200;
} else {
status_code = 401;
}
res.status(status_code).json(json_object);
//console.log("response ="+response+" & message = "+ message);
});
login.component.ts
import { Component, OnInit } from '#angular/core';
import { NgForm } from '#angular/forms';
import { AuthData } from 'src/app/Models/auth_data.model';
import { LoginModel } from 'src/app/Models/login_details.model';
import { ResponseFromServer } from 'src/app/Models/response.model';
import { AuthService } from 'src/app/Services/auth.service';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
isSubmitted = false;
isValid = true;
isLoading = false;
response_from_server = new ResponseFromServer();
constructor(private authService: AuthService) {
}
ngOnInit(): void {
this.response_from_server.response = 's1';
}
loginUser(loginData: NgForm) {
this.isSubmitted = true;
if(loginData.invalid) {
this.isValid = false;
//console.log("Validation Errors");
return;
}
const loginDetails : LoginModel = {
username : loginData.value.username,
password: loginData.value.password
}
this.authService.checkUserLogin(loginDetails);
}
}
Whenever I try to login , the error TypeError: Cannot read properties of undefined (reading 'length') is thrown.
The data is not even sent to the server side. It is stuck before return next.handle(authRequest);.
I tried console.log() almost everywhere to see where I am getting the mistake, and to which part, the data movement is getting done. Looks like the email and password are not even going through, to the Node JS server. Using console.log(result.token) in login.service.ts does not have any value.
Where am I going wrong ?
The problem is most likely happening because your trying to add the Authorization header before the user is logged-in.
In that situation authToken is undefined and you are assigning it to the header anyways.
You could solve it just adding a guard in your intercept method to first check if you have an authToken before attaching it to the request.
intercept(req: HttpRequest<any>, next: HttpHandler) {
const authToken = this.authService.getAuthToken();
if(!authToken) { // <--- not logged-in skip adding the header
return next.handle(req);
}
const authRequest = req.clone({
headers: req.headers.set("Authorization", authToken)
});
return next.handle(authRequest);
}
Cheers

How to apply authorization to whole controller except one method

I have added an AuthGuard on the UsersController class but I want to exclude one method in this controller from authorization.
Is it possible to exclude a single method from authorization?
I have added my code below:
#UseGuards(AuthGuard('jwt'))
#ApiUseTags('Users')
#Controller('users')
export class UsersController {
constructor(public service: UsersService) {}
get base(): CrudController<UsersService, UserEntity> {
return this;
}
#Override()
async createOne(#ParsedParams() params, #ParsedBody() body: UserEntity) {
const username = body.username, email = body.email;
const qb = await getRepository(UserEntity)
.createQueryBuilder('users')
.where('users.username = :username', { username })
.orWhere('users.email = :email', { email });
const _user = await qb.getOne();
if (_user) {
const error = { username: 'username already exists' };
throw new HttpException({ message: 'Input data validation error', error }, HttpStatus.BAD_REQUEST);
}
return this.base.createOneBase(params, body);
}
#Post(':id/avatar')
#UseInterceptors(FileInterceptor('file', {
storage: multerDiskStorageConfig('users', 'avatar'),
}))
async uploadAvatarFile(#Param() params, #UploadedFile() file: any) {
const userObject = await this.base.service.findOne();
userObject.avatar = file.path.replace(PUBLIC_ROOT_PATH, '');
return this.base.updateOneBase(params, userObject);
}
}

Unauthorization to protected route when request is made from Angular to Node

User.js (backend)
//profile
router.get('/profile', passport.authenticate('jwt', { session: false }), (req, res) => {
res.json({
user: req.user,
})
});
Angular
Login Component:
//onLoginSubmit() is a event Based function
onLoginSubmit(){
const user ={
username:this.username,
password:this.password
}
this._authService.authenticateUser(user).subscribe(data=>{
console.log(data);
this._dataServiceData=data;
if(this._dataServiceData.success){
this._authService.storeUserData(this._dataServiceData.token,this._dataServiceData.user);
this._flahMessage.show('You are now Logged in !',{cssClass:'alert-success',timeout:3000});
this._router.navigate(['dashboard']);
}else{
this._flahMessage.show(this._dataServiceData.msg,{cssClass:'alert-danger',timeout:3000});
this._router.navigate(['login']);
}
});
}
On success The return of the data of subscribe is an object:
success:true
token:"bearer aGh..........Q2rEjhnZ6XjXVKmwNFoiWFjEJk"
Then if i am accessing the private Route e.g(profile) than it is unauthorizing it
Profile Component
export class ProfileComponent implements OnInit {
private _dataService:any={};
public user={};
constructor(private _authService:AuthService,
private _router:Router) { }
ngOnInit() {
this._authService.getProfile().subscribe(data=>{
console.log(data);
this._dataService=data;
this.user = this._dataService.user;
},err=>{
console.log(err);
return false;
})
}
}
The AuthService(Injected to all)
_/**
authenticateUser(user){ **called from loginComponent**
let headers = new HttpHeaders();
headers.append('content-type','application/json');
return this.http.post('http://localhost:8080/users/authenticate',user,{headers:headers})
}
getProfile(){ **called from profileComponent**
let headers = new HttpHeaders();
this.loadToken();
headers.append('Authorization',this.token);
headers.append('content-type','application/json');
return this.http.get('http://localhost:8080/users/profile',{headers:headers})
}
loadToken(){
const token = localStorage.getItem('id_token');
this.token=token;
}
storeUserData(token,user){
localStorage.setItem('id_token',token);
localStorage.setItem('user',JSON.stringify(user));
this.token = token;
this.user=user;
}
GitHub Repository link
While i am accessing the protected Route the error is :
Http failure response for http://localhost:8080/users/profile: 401 Unauthorized

how to get jwt token from access token in auth0

I am developing angular2-nodejs-mongodb single page application.and using auth0 security.
I got access_token from angular2 project. But it's not jwt_token. Main problem is node.js project want jwt_token like Authorization : Bearer My_Token. Attached image below.
Angular image :getting access_token
postman:send requires to auth0 for jwt_token
postman : try to access my nodejs aaplication
Actually I did't get idea, how to convert angular access token to node.js jwt_tocken
Let's just say I found this solution on internet
Actually copied some code from private repo)
const createClient = () => createAuth0Client({
domain: AUTH0_DOMAIN,
client_id: AUTH0_ID,
redirect_uri: window.location.origin,
});
...
export class AuthService {
constructor(
public sessionService: SessionService,
public alertService: AlertService,
public userService: UserService,
) {
makeObservable(this, {
sessionService: observable,
alertService: observable,
userService: observable,
authPopup: action.bound,
authRedirect: action.bound,
_handleNewToken: action.bound,
init: action.bound,
});
this.init();
}
async _handleNewToken(auth0: Auth0Client) {
const {
_raw: jwt,
nickname,
picture,
email,
} = await auth0.getIdTokenClaims();
nickname && this.userService.setNickname(nickname);
picture && this.userService.setPicture(picture);
email && this.userService.setEmail(email);
this.sessionService.setSessionId(jwt);
// ^^^
}
async authPopup() {
let token: string | false = false;
try {
const auth0 = await createClient();
await auth0.loginWithPopup();
await this._handleNewToken(auth0);
this.alertService.push('Signed in successfully');
} catch (e) {
console.log(e);
this.alertService.push('Authorization failed');
} finally {
return token;
}
}
async authRedirect() {
try {
const auth0 = await createClient();
await auth0.loginWithRedirect();
await sleep(5_000);
} catch(e) {
console.log(e);
this.alertService.push('Authorization failed');
}
}
async init() {
try {
const auth0 = await createClient();
await auth0.handleRedirectCallback();
await this._handleNewToken(auth0);
this.alertService.push('Signed in successfully');
} catch (e) {
console.log(e);
}
}
};
...
const handleButtonClick = () => {
await authService.authRedirect();
...
};

Resources