Angular 2 Facebook Authentication - javascript

I´m triying to implement facebook authenticathion from my angular 2 app but I think I'm implenting in the wrong way and I can't find some tutorials about this and also I want to ask if ¿is Auth0 the only way to implement this?.
Well I have this:
Node JS server :
// FB authentication
authRoutes.get('/facebook', passport.authenticate('facebook', { session : false, scope: ['email'] }))
authRoutes.get('/facebook/callback', passport.authenticate('facebook', { session : false, failureRedirect: '/'}), ctrlAuthentication.facebookResponse)
these are the routes in the api and I'm using passportjs, all works when I call the api directly in the browser like: localhost:3000/api/auth/facebook and I get the user returned from the api in JSON format.
Now in the front I have angular 2 and this is
authentication.service.ts:
import {User} from '../_models/user'
#Injectable()
export class AuthenticationService {
public token : String;
public user : User;
constructor(private http: Http){
}
fbLogin() : Observable<User> {
let user = this.http.get('/api/auth/facebook')
.map(this.mapUser);
return user;
}
mapUser(response : Response) : User {
console.log(response)
let data = response.json();
this.token = data.token;
let user = <User>(data.user);
this.user = user;
localStorage.setItem('currentUser', JSON.stringify({ user: user, token: data.token }));
return user;
}
}
and this is the register.component.ts:
import {AuthenticationService} from '../_services/authentication.service'
import {User} from '../_models/user'
#Component({
selector: 'crowd-register',
templateUrl: 'app/RegisterComponent/register.component.html'
})
export class RegisterComponent {
private user : User;
constructor(
private authenticationService : AuthenticationService
) {}
fbLogin() {
this.authenticationService.fbLogin().subscribe(
user => {
this.user = user;
}
)
}
}
When I call fbLogin() from the app I get this error:
SyntaxError: Unexpected token < in JSON at position 0
MapSubscriber.AuthenticationService.mapUser [as project] (authentication.service.ts:46)
I think this is because I'm don't getting the user from my api, I'm getting the response from facebook and this isn't executing or something.
This is the picture of the console.log(response) and the error.
Thanks for all answers, sorry for my english.

Related

How to handle the Internal server error? Nestjs

How to handle the error so that if the user does not provide a token, then an UnauthorizedException is thrown.
At the moment I am getting this error:
{
"statusCode": 500,
"message": "Internal server error"
}
ts:
canActivate(context: ExecutionContext) {
const request = context.switchToHttp().getRequest();
try {
const jwt = request.headers.authorization.split(' ')[1];
if (!jwt) {
throw new UnauthorizedException('Token is not provided.');
}
return this.jwtService.verify(jwt);
} catch (e) {
return false;
}
}
You can try to recreate auth module from the documentation.
Or try to console.log() on each line.
By default, JWT internal module works well. It can encode and decode all that you need automatically.
https://docs.nestjs.com/security/authentication
I use a middleware for this purpose. I'll share a basic version of it.
auth-middleware.ts
import {HttpStatus,Injectable,Logger,LoggerService,NestMiddleware,} from '#nestjs/common';
import { NextFunction } from 'express';
import { Request, Response } from 'express';
#Injectable()
export class AuthMiddleware implements NestMiddleware {
constructor(
private readonly authenticationService: AuthService,
// (I use Firebase auth. You can inject JWT service here instead)
private readonly logger: LoggerService, // Good'ol logger
) {}
public async use(req: Request, res: Response, next: NextFunction) {
// Checks if req has authorization header
const header = req.headers['authorization'];
if (!header) {
// If no headers are present, returns a 401.
// I use problem+json
// Thats why you are seeing more fields in the response instead of just a
// code and message
return res
.status(HttpStatus.UNAUTHORIZED)
.json({
title: 'Unauthorized',
detail: 'Invalid Token',
type: 'https://app-site.com/login',
status: HttpStatus.UNAUTHORIZED,
instance: 'login/null',
})
.setHeader('Content-Type', 'application/problem+json');
}
// Splitting "Bearer token" to ["Bearer","token"]
const token = header.split(' ')[1];
// Validating token with auth service
// It returns a "tuple" for me...you can have it return whatever you want
const [
authClaims, // Custom claims that is extracted from the JWT
result, // JWT Validation result (boolean)
authProviderUid, // Firebase UID
] = await this.authenticationService.verifyToken(token);
if (
!result || // If JWT is invalid
authClaims.accountStatus === AccountStatusList.Banned ||
authClaims.accountStatus === AccountStatusList.Suspended
) {
// You shall not pass
return res
.status(HttpStatus.UNAUTHORIZED)
.json({
title: 'Unauthorized',
detail: 'Invalid Token',
type: 'https://app-site.com/login',
status: HttpStatus.UNAUTHORIZED,
instance: 'login/null',
})
.setHeader('Content-Type', 'application/problem+json');
}
// Attaches the claims, result and UID with req for the next middleware(s)/controller
req['authResult'] = { authClaims, result, authProviderUid };
//Reassuring
this.logger.log('Token verified', AuthMiddleware.name);
// next function from express
next();
}
}
Next, In the module(s) your controllers are declared,
api.module.ts
import { MiddlewareConsumer, Module, NestModule, RequestMethod, } from '#nestjs/common';
#Module({
imports: [
//...
],
controllers: [
AuthController,
ProfileController,
SubscriptionController
],
providers: [
//...
],
})
export class ApiModule implements NestModule {
public async configure(consumer: MiddlewareConsumer) {
consumer
.apply(AuthMiddleware)
// Exclude some paths
.exclude({ path: '/api/v1/auth/sign-up', method: RequestMethod.POST })
.forRoutes( // Your controller classes you want to run the middleware on
ProfileController,
SubscriptionController,
AuthController
);
}
}
How it works
Every request goes through the specified middleware (if path not excluded). If the request is unauthorized, throws an error before it reaches the controller.
If the request is at the controller, the request is authenticated. You have to take care of the authorization part with guards etc...
Authentication and Authorization are different.
I'd suggest to use middleware for authentication and guards for authorization.
Links :
NestJS Middleware Documentation
Problem Details

Show login modal on unauthorized response angular 7

I need to show a login modal every time the server returns a http unauthorized status (401), and in that case, stop the page loading... for example, I'm logged in but trying to access an protected resource that only admin users can do it.. so in that case I would like to show an modal with login and password to the user. It could be on navigating to a protected route or on delete event for example.
I tried to do it in an ApiInterceptor:
#Injectable({providedIn: 'root'})
export class ApiInterceptor implements HttpInterceptor {
constructor(
...
) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
req = req.clone({ url: environment.baseUrl + req.url });
if (this.authService.validToken) {
req = req.clone({ headers: req.headers.set('Authorization', `Bearer ${this.authService.validToken}`) });
}
if (!req.headers.has('Content-Type')) {
req = req.clone({ headers: req.headers.set('Content-Type', 'application/json') });
}
return next.handle(req).pipe(catchError(resp => this.handleError(resp)));
}
private handleError(httpError: HttpErrorResponse) {
if (httpError.status === this.UNAUTHORIZED) {
// opening login modal here, but can't stop the request to prevent user to se unauthorized data, and after login, how can I redirect user to the same resource he tried to access?
}
return throwError(httpError);
}
}
Need help here, if someone have an idea in how to do it will be appreciated!
Your ApiInterceptor looks like it's for adding a bearer token to the request. I'd call this the TokenInterceptor or similar, and create a new one for handling unauthorised requests.
I'd create a new interceptor and call this UnauthorisedRequestInterceptor. Something similar to this:
#Injectable({ providedIn: 'root' })
export class UnauthorisedRequestInterceptor implements HttpInterceptor {
constructor(private router: Router) { }
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
return next.handle(req).pipe(
map(event => {
return event;
}),
catchError((error: HttpErrorResponse) => {
if (error.status === 401) {
this.router.navigate(['/auth/login']);
}
return throwError(error);
})
);
}
}
This will intercept every http request, and if the returned status is 401, it will redirect you to your login page.
Then add this into your list of providers in app.module.ts:
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: UnauthorisedRequestInterceptor,
multi: true
}
]
As for redirecting users on access to a protected route, this should be done in your auth guard.
Every protected data that need roles or permissions should be on the server & have specific authorization to access it, if there is already protected data on your application you should consider moving it onto your server or add at least a guard.
If you want to redirect the user after a 401 you have to inject the Router service in your interceptor & use the navigate function (cf this.router.navigate(['/myRoute']); )

Angular Auth Guard after Login does not get observable informations

I implemented a login in angular.
It works well, but I like to redirect after successfully authentication.
The redirect does not work after receiving the user from server.
If I refresh my page and use the login, it works.
I receive an object from my webservice and save it to "localStorage".
I use a BehaviourSubject to observe my current user.
If I press 'login' i run into auth guard, but the auth guard does not know the user. (its null)
What is my mistake?
Auth.guard.ts
#Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
constructor(
private router: Router,
private authenticationService: AuthService
) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
console.log(this.authenticationService.currentUserValue);
if (this.authenticationService.currentUserValue) {
return true;
}
// not logged in so redirect to login page with the return url
this.router.navigate(['/entrance/login'], { queryParams: { returnUrl: state.url } });
return false;
}
}
#Injectable({
providedIn: 'root'
})
export class AuthService {
private currentUserSubject: BehaviorSubject<User>;
constructor(private http: HttpClient) {
this.currentUserSubject = new BehaviorSubject<User>(JSON.parse(localStorage.getItem('currentUser')));
}
public get currentUserValue(): User {
return this.currentUserSubject.value;
}
login(username: string, password: string) {
return this.http.post<User>('/api/auth', { username, password }).pipe(map(user => {
// login successful if there's a jwt token in the response
if (user && user.token) {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify(user));
this.currentUserSubject.next(user);
}
return user;
}));
}
this.authService.login(email, password).pipe(first()).subscribe(data => {
this.router.navigate([this.returnUrl]);
});
I like to redirect directly after login without refresh.
You see any mistakes?

Value is undefined when subscribing to service

I have this problem. When I am trying to subscribe to a data returned from service I get undefined when trying to log it.
This is my route, I have tested it with REST client and it works fine:
router.post('/liveAuction', (req, res, next) => {
const id = req.body.id;
Auction.getAuctionById(id, (err, liveAuction) => {
if (err){
res.json({
success: false,
message: "Something went wrong!"
});
console.log(err);
}
else {
res.json({
success: true,
message: "Auction retrieved!",
liveAuction
});
}
});
});
This is my method of getting data from mongoDB:
module.exports.getAuctionById = function(id, callback){
const query = {_id: id};
Auction.find(query, callback);
console.log(query);
}
This is my service:
getAuctionById(id):any{
let headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.post('http://localhost:3000/auctions/liveAuction', {id: id}, {headers: headers})
.map(res => res.json());
}
And this is my component.ts:
import { Component, OnInit, ElementRef, Inject } from '#angular/core';
import { Observable } from 'rxjs/Rx';
import {Router, RoutesRecognized} from '#angular/router';
import { AuctionService } from '../../services/auction.service';
import { DataTransferService } from '../../services/data-transfer.service';
#Component({
selector: 'app-auction-details',
templateUrl: './auction-details.component.html',
styleUrls: ['./auction-details.component.css']
})
export class AuctionDetailsComponent implements OnInit {
liveAuction: any;
auction: any;
id: any;
constructor(
private auctionService: AuctionService,
private dataService: DataTransferService
) {
this.dataService.currentProduct.subscribe(auction => this.auction = auction);
this.id = this.auction._id;
console.log(this.auction._id);// I get the right id here.
}
ngOnInit() {
this.auctionService.getAuctionById(this.id).subscribe(auction => this.liveAuction = auction.liveAuction);
console.log(this.liveAuction);// Here I get undefined.
Also if I try to use get items of it, like this.liveAuction._id, I get "Cannot find property _id of undefined" error.
Could you help me understand what I am doing wrong? I have done similar procedure for my other component which I use as Mat-Dialog component with different service, but functionality is completely the same. I have compared them like three times already and everything looks same but here it doesn't work. Please suggest what I am doing wrong. Thanks!

Angular2 Http Call not firing

Context :
Following several tutorials, I am testing authentication with Angular2 and JWT. I come with a component and a service :
app.component.ts
user.service.ts
App component (and template) contains the subscription to an observable that shows the user logged in status. The Observable item is kept in the user service, and changes (fine) when user logs in and out.
The authentication token is written in "localStorage" as "auth_token". It contains a validity value (time) that should force the user to login again after a time.
What I'd like to do is to CHECK the token validity on app init. First, I tried to do it from the user.service CONSTRUCTOR, then (fail), I tried to do it from ngOnInit in the app.component, then (fail again), I tried to do it on event call (click on a button) from the app component, but fails again!
Some shortened code :
//app.component.html
//...
<a md-button class="app-icon-button" aria-label="checklogin" (click)="checkLogin()">
<md-icon svgIcon="check"></md-icon>
</a>
//...
//app.component.ts
//...
checkLogin(){
console.log('CHECK LOGIN FUNCTION');
let token = localStorage.getItem('auth_token');
if(token){
console.log('TOKEN FOUND');
this.userService.checkToken(token);
}else{
console.log('NO TOKEN FOUND');
}
}
//...
//user.service.ts
//...
checkToken(token){
console.log('CHECK TOKEN FUNCTION');
console.log('TOKEN : '+token);
let headers = new Headers();
headers.append('Content-Type','application/json');
return this.http
.post(
'/url/script.php',
JSON.stringify(token),
{ headers }
)
.map(res => res.json())
.map((res) => {
console.log('SCRIPT RESULT : ');
if(res.valid){
console.log('TOKEN IS VALID');
return true;
}else{
console.log('TOKEN NOT VALID');
return false;
}
});
}
//...
I did skip the observable part, and subscription.
Problem :
The problem actually is that the app NEVER CALLS the script!
When I do click on the "checkLogin" button (when token exists),
console shows 'CHECK LOGIN FUNCTION',
console shows 'TOKEN FOUND',
console shows 'CHECK TOKEN FUNCTION',
console shows 'TOKEN : '****************************** (token),
But it never shows 'SCRIPT RESULT',
and when using firebug to check if the http call is done, there is NO CALL to the script.php. Looks like the this.http part is just ignored...
Thanks for reading/help
Service starts working when subscription used only when consumer subscribe to output result, using .subscribe method.
You need: this.userService.checkToken(token).subscribe()
Your checkToken() method is returning an Observable that you need to subsrcibe to. An observable will never to execute unless it's subscribed to.
checkLogin(){
console.log('CHECK LOGIN FUNCTION');
let token = localStorage.getItem('auth_token');
if(token){
console.log('TOKEN FOUND');
this.userService.checkToken(token).subscribe(result => {
console.log(result);
}),
error => {
console.log(error);
});
} else {
console.log('NO TOKEN FOUND');
}
}
Ajax call's which use Observables will work only if you have an subscriber.
So you need to subscribe to that Observable. It is an Angular 2 feature. When you don't subscribe the Observable, it will never make that call.
And also you don't need to return anything from the subscriber, because you actually can't return anything.
this.userService.checkToken(token).subscribe((res) => {
console.log('SCRIPT RESULT : ');
if(res.valid) {
console.log('TOKEN IS VALID');
} else {
console.log('TOKEN NOT VALID');
}
});
checkToken(token){
console.log('CHECK TOKEN FUNCTION');
console.log('TOKEN : '+token);
let headers = new Headers();
headers.append('Content-Type','application/json');
return this.http
.post(
'/url/script.php',
JSON.stringify(token),
{ headers }
)
.map(res => res.json());
}
Have You tried using Postman and try to call function you need?
Also, why do You need to validate a token if angular2-jwt can do this for You?
You can do just like this:
install angular2-jwt with npm.
Include in app.module.ts:
import { AUTH_PROVIDERS } from 'angular2-jwt';
add to providers:
providers: [
AUTH_PROVIDERS,
],
and for example auth.service.ts looks like this:
import { Injectable, Inject } from '#angular/core';
import { Http, Response, Headers, RequestOptions, RequestMethod } from '#angular/http';
import { Router } from '#angular/router';
import { Observable } from 'rxjs/Observable';
import { Configuration } from '../../app.config';
import { RegisterViewModel } from '../../model/viewModel/registerViewModel';
import { LoginViewModel } from '../../model/viewModel/loginViewModel';
import { tokenNotExpired, AuthHttp } from 'angular2-jwt';
#Injectable()
export class AuthService {
private actionUrl: string;
constructor(private _http: Http, private _config: Configuration, private _router: Router, private _authHttp: AuthHttp){
this.actionUrl = _config.apiUrl;
}
register(user: RegisterViewModel){
let headers = new Headers({ 'Content-Type': 'application/json' });
//Admin in this system can only register users. that is why auth
return this._authHttp.post(this.actionUrl + '/Account/Register', JSON.stringify(user), { headers : headers })
.do(response => {
console.log(response.toString());
});
}
login(user: LoginViewModel) {
let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
return this._http.post('http://localhost:56181/api/token', "username=" + user.userName + "&password=" + user.password + "&userId=" + user.userId, { headers : headers })
.do(response => {
if(response){
let authResult = response.json();
this.setUser(authResult);
this._router.navigate(['']);
}
});
}
public isAuthenticated(): boolean {
//angular2-jwt has this function to check if token is valid
return tokenNotExpired();
}
private setUser(authResult: any): void {
localStorage.setItem('id_token', authResult.id_token);
}
public logout(): void {
localStorage.removeItem('id_token');
this._router.navigate(['']);
}
}
also remember that angular2-jwt has default name for token in localstorage as id_token or else you will have to use angular2-jwt help class to specify other token name.
You can check if it is working by simply doing this:
in app.component.ts:
export class AppComponent {
constructor(private _auth: AuthService){
}
}
and in app.component.html:
<li>
<a class="nav-link" [routerLink]="['/login']" *ngIf="!_auth.isAuthenticated()">Login</a>
</li>
<li>
<a class="nav-link" (click)="_auth.logout()" *ngIf="_auth.isAuthenticated()">Log Out</a>
</li>
also You can read a little bit documentation about it in:
https://auth0.com/blog/introducing-angular2-jwt-a-library-for-angular2-authentication/

Categories

Resources