Skip to content

Instantly share code, notes, and snippets.

@ricalamino
Created October 16, 2018 13:59
Show Gist options
  • Save ricalamino/588b7a8175d91d4968ebbf6b66cb94af to your computer and use it in GitHub Desktop.
Save ricalamino/588b7a8175d91d4968ebbf6b66cb94af to your computer and use it in GitHub Desktop.
Auth0 Auth custom
<input class="sign-up__form-input" type="email" name="email" id="email" placeholder="{{ 'Email' }}"
[(ngModel)]="email" (keyup.enter)="keytab($event)">
<input class="sign-up__form-input" type="password" name="password" id="password" placeholder="{{ 'Password' }}"
[(ngModel)]="password" (keyup.enter)="keytab($event)">
<button >{{ 'ForgotPassword' }}?</button>
<button id="login_submit" class=""
(click)="loginNoLock(email, password)">
{{ 'SignInLogin' }}
</button>
<p>Para se registrar, preencha o nome também</p>
<input class="sign-up__form-input" type="text" name="nome" id="nome" placeholder="{{ 'Seu Nome' }}"
[(ngModel)]="nome" (keyup.enter)="keytab($event)">
<button id="signup_submit" class=""
(click)="signUpNoLock(email, password, nome)">
{{ 'SignUp' }}
</button>
<button id="signup_submit" class=""
(click)="loginFacebook(email, password, 'facebook')">
{{ 'LoginFacebook' }}
</button>
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { environment } from '@env/environment';
import { LoginStatusEnum, LoginStatusService } from '@gorila/core';
import { LoginRoutePathUrl } from '@gorila/core/router';
import { AnalyticsService, BaseComponent } from '@gorila/core/utils';
import { TranslateService } from '@ngx-translate/core';
import { path } from 'ramda';
import { filter } from 'rxjs/operators/filter';
import { take } from 'rxjs/operators/take';
import * as auth0 from 'auth0-js';
import { Auth0Config } from '../config/auth0.config';
import { AuthService } from '../services/auth.service';
import { FormGroup, FormControl, Validators } from '@angular/forms';
/**
* the auth0 locker not loaded problem can be fixed migrating to requirejs:
* let Auth0Lock = require('auth0-lock').default; instead
* declare var Auth0Lock: any;
* but it needs some refactor level
*/
declare var Auth0Lock: any;
@Component({
selector: 'auth',
templateUrl: './auth.component.html',
styleUrls: ['./auth.component.scss']
})
export class AuthComponent extends BaseComponent implements OnInit {
public message: string;
private lock = null;
public signin: FormGroup;
public email: string;
public password: string;
public nome: string;
public auth0 = new auth0.WebAuth({
domain: environment.Auth0.domain,
clientID: environment.Auth0.clientID,
redirectUri: environment.Auth0.redirectUrl,
audience: environment.Auth0.audience,
responseType: environment.Auth0.responseType,
scope: environment.Auth0.scope,
});
constructor(
private authService: AuthService,
private loginStatusService: LoginStatusService,
private translate: TranslateService,
private router: Router
) {
super();
}
public getName(): string {
return 'AuthComponent';
}
public ngOnInit() {
/*this.updateMessage('Wait, the gorillas are building the app');
this._attach(this.loginStatusService.getObserver().subscribe(() => {
const data = this.loginStatusService.getCurrentValue();
if ([LoginStatusEnum.Error, LoginStatusEnum.Auth0NotLogged].indexOf(data['code']) !== -1) {
this.initLocker();
return this.lockShowOnError(data);
}
}));
this.subscribeAuthService();*/
}
private lockShowOnError(data) {
if (data.code !== LoginStatusEnum.Error) { return ; }
const value = this.authService.getLocker().getValue();
if (!!path(['flashMessage', 'text'], value)) {
value.flashMessage.text = this.translate.instant(value.flashMessage.text);
}
if (!!value) {
this.showLocker(value);
}
}
private destroyLocker() {
try {
if (!!this.lock) {
this.lock.destroy();
}
} catch (e) { console.warn(e); }
}
private initLocker() {
try {
// if locker already exists
if (!!this.lock) { return; }
// Instantiate a new locker
if (!Auth0Lock) { return; }
this.lock = new Auth0Lock(environment.Auth0.clientID, environment.Auth0.domain, Auth0Config);
// Set up locker events listener
this.autenticatedEvent();
this.errorEvent();
} catch (e) { console.warn(e); }
}
private loginNoLock(username, password) {
this.authService.loginNoLock(username, password);
}
private signUpNoLock(username, password, nome) {
this.authService.signUpNoLock(username, password, nome);
}
private loginFacebook(username, password, social) {
this.authService.loginSocial(username, password, social);
}
public resetPassword(email): void {
this.auth0.changePassword({
connection: 'Username-Password-Authentication',
email: email,
}, (err) => {
if (err) {
console.log(err);
return;
} else {
console.log('Password reset link sent!');
}
});
}
private autenticatedEvent() {
// Add callback for lock `authenticated` event
this.lock.on('authenticated', (authResult: any) => {
this.lock.getUserInfo(authResult.accessToken, (error: any, profile: any) => {
if (error) {
console.warn('Error loading the Profile', error);
return;
}
return this.runAutentication(authResult, profile);
});
});
}
private runAutentication(authResult: any, profile: any) {
try {
if (!environment.features.emailVerification ||
(profile && profile.email_verified)
) {
this.authService.authenticationCompleted(profile, authResult['idToken']);
this.redirectToLoadingRoute();
return true;
}
if (profile['user_id']) {
AnalyticsService.setUser(profile['user_id']);
}
this.authService.displayError({error_description: 'EmailNotVerified'});
return false;
} catch (e) { console.warn(e); }
}
private subscribeAuthService() {
this._attach(this.authService.getLocker()
.pipe(filter(() => !!this.lock))
.subscribe(showConfig => this.showLocker(showConfig)));
}
// auth0 error
private errorEvent() {
this.lock.on('authorization_error', (error => {
if (environment.features.emailVerification && this.isEmailNotVerifiedError(error)) {
return;
}
let text = typeof error['description'] !== 'undefined' ? error['description'] : '';
if (typeof error['error_description'] !== 'undefined') {
text = error['error_description'];
}
if (text === '') {
text = this.translate.get('Auth0CantLogin');
}
this.authService.displayError({error_description: text});
}));
this.lock.on('unrecoverable_error', console.error);
}
private updateMessage(message: string) {
this.translate.get(message).pipe(take(1)).subscribe(m => this.message = m);
}
private isEmailNotVerifiedError(error: any) {
if (!error || !error['description']) {
return false;
}
const temp = JSON.parse(error['description']);
if (!temp || !temp['uid']) {
return false;
}
AnalyticsService.setUser(temp['uid']);
this.authService.displayError({error_description: 'EmailNotVerified'});
return true;
}
private showLocker(showConfig) {
this.lock.show(showConfig);
}
private redirectToLoadingRoute = () => this.router.navigate([LoginRoutePathUrl]);
}
import { Injectable } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { JwtHelperService } from '@auth0/angular-jwt';
import { environment } from '@env/environment';
import { AppConstants } from '@gorila/constants';
import { LoginStatusEnum, LoginStatusService } from '@gorila/core';
import { ManagerRoutePath } from '@gorila/core/router';
import { AnalyticsService, CookieService, UtilsService } from '@gorila/core/utils';
import { FundType, UserDataActions, UserDataSelectors, UserDataState } from '@gorila/root-store/user-data';
import { LoginService } from '@gorila/shared';
import { LogService } from '@gorila/shared/services/log.service';
import { SocketEventService, SocketService } from '@gorila/socket';
import { Store, select } from '@ngrx/store';
import { path, toString } from 'ramda';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { timer } from 'rxjs/observable/timer';
import { filter } from 'rxjs/operators/filter';
import { skip } from 'rxjs/operators/skip';
import { take } from 'rxjs/operators/take';
import { of } from 'rxjs/observable/of';
import { delay } from 'rxjs/operators/delay';
import { takeUntil } from 'rxjs/operators/takeUntil';
import { Subscription } from 'rxjs/Subscription';
import { authStatusDefault, AuthStatusType, MockedIdToken, MockedUser } from './auth.model';
import { HttpHeaders, HttpClient } from '@angular/common/http';
/**
* IF YOU NEED AUTO FILL user email in auth0 locker
* https://bitbucket.org/snippets/gorilainvest/qebq7z
*/
@Injectable()
export class AuthService {
private lockerSubject = new BehaviorSubject<any>({});
private authStatus = new BehaviorSubject<AuthStatusType>(authStatusDefault);
private firstLogin = false;
private loggedFundType: FundType;
private source: string;
private routeURL = '.';
private subscriptions: { [s: string]: Subscription } = {};
constructor(
private loginService: LoginService,
private router: Router,
private socketEventService: SocketEventService,
private socketService: SocketService,
private route: ActivatedRoute,
private jwtHelper: JwtHelperService,
private loginStatusService: LoginStatusService,
private store: Store<UserDataState.State>,
private http: HttpClient,
) {
this.route.queryParams.pipe(
skip(1),
take(1),
takeUntil(timer(1000))
).subscribe((queryParams: {[key: string]: any}) => {
localStorage.setItem('utm', JSON.stringify(queryParams));
AnalyticsService.setEvent('utm', { ...queryParams });
});
if (!this.runMock()) {
}
this.handleLoginState();
}
private runAutentication(authResult: any, profile: any) {
try {
if (!environment.features.emailVerification ||
(profile && profile.email_verified)
) {
console.log('Thomas');
this.authenticationCompleted(profile, authResult['id_token']);
this.router.navigate(['/entrando']);
return true;
}
if (profile['user_id']) {
AnalyticsService.setUser(profile['user_id']);
}
this.displayError({error_description: 'EmailNotVerified'});
return false;
} catch (e) { console.warn(e); }
}
public authenticationCompleted(authResult: any, idToken: string) {
try {
localStorage.setItem('id_token', idToken);
this.onAutenticate(authResult, idToken);
} catch (e) {
console.warn(e);
}
}
public getLocker() {
return this.lockerSubject;
}
// LOGIN NO LOCK MAGICALLY WORKING
public loginNoLock(username: string, password: string): void {
const postData = {
username,
password,
client_id: environment.Auth0.clientID,
connection: 'Username-Password-Authentication',
scope: environment.Auth0.scope
};
const req = this.http.post('https://' + environment.Auth0.domain + '/oauth/ro', postData, {
headers: new HttpHeaders().set('Content-Type', 'application/json')
});
req.subscribe((data: any) => {
console.log(data);
const userinfoReq = this.http.get(environment.Auth0.audience, {
headers: new HttpHeaders().set('Authorization', 'Bearer ' + data.access_token)});
userinfoReq.subscribe((data_user: any) => {
console.log(data_user);
this.runAutentication(data, data_user);
});
}, err => {
console.log(err);
});
}
public loginSocial(username: string, password: string, social: string): void {
const req = this.http.get('https://' + environment.Auth0.domain + '/authorize', {
headers: new HttpHeaders(
{'Origin': 'https://localhost:4200',
'Access-Control-Request-Method': 'POST',
'Access-Control-Request-Headers': 'Content-Type, Authorization',
}),
params: {
response_type: 'token',
client_id: environment.Auth0.clientID,
connection: social,
redirect_uri: environment.Auth0.redirectUrl
}
});
req.subscribe((data: any) => {
console.log(data);
}, err => {
console.log(err);
});
}
public signUpNoLock(username: string, password: string, name: string) {
const postData = {
client_id: environment.Auth0.clientID,
email: username,
password,
connection: 'Username-Password-Authentication',
user_metadata: { name }
};
const req = this.http.post('https://' + environment.Auth0.domain + '/dbconnections/signup', postData, {
headers: new HttpHeaders().set('Content-Type', 'application/json')
});
req.subscribe((data: any) => {
console.log(data);
this.loginNoLock(username, password);
}, err => {
console.log(err);
});
}
public logout() {
this.firstLogin = false;
this.source = null;
AnalyticsService.unsetUser();
this.socketService.clear();
this.loginStatusService.updateStatus(LoginStatusEnum.UserLogoutStarted);
this.store.pipe(select(UserDataSelectors.selectFeatureUser), take(1)).subscribe(user => {
if (!path(['data', 'token'], user)) {
return this.logoutDone();
}
this.loginService.logoutUser().pipe(take(1)).subscribe(
() => this.logoutDone(),
(error) => {
console.warn(error);
this.logoutDone();
}
);
});
}
public authenticated(): boolean {
return this.isMocked() ? true : !!this.getAuthToken();
}
public displayError(error: any) {
this.loginStatusService.updateStatus(LoginStatusEnum.Error);
this.lockerSubject.next({
flashMessage: {
type: 'error',
text: !error['error_description'] || toString(error['error_description']) === '' ? 'Unknown Error' : error['error_description']
}
});
}
private handleLoginState() {
// do not unsubscribe from this listener. It must listen while app run
this.authStatus.pipe(filter(data => !!data)).subscribe(data => {
LogService.loginStatusLog('$$$', {...data});
if (!!data.error) {
return this.handleError(data);
}
if (!data.auth0) {
return this.handleAuth0();
}
if (!data.signup) {
return this.handleSignup();
}
if (!data.login) {
if (environment.unstableLogin) {
this.changeAuthStatus('login', true);
}
return this.handleLogin();
}
if (!data.ws) {
if (environment.unstableLogin) {
this.changeAuthStatus('ws', true);
}
return this.handleSocket();
}
this.handleUserLogged();
});
if (!this.loginFromStorage()) {
this.loginByUrl();
}
}
private handleError(data) {
const errorStatus = path(['error', 'status'], data);
const status = toString(errorStatus || data.status);
switch (status) {
case '401': {
data.error = {
...data.error,
error_description: (!!path(['error', 'statusText'], data)) ? data.error.statusText : 'Auth0TokenNotRecognized'
};
break;
}
}
this.displayError(data.error);
}
private handleAuth0() {
this.lockerSubject.next({});
this.loginStatusService.updateStatus(LoginStatusEnum.Auth0NotLogged, null, true);
}
private handleSignup() {
this.loginService.createUser().pipe(take(1)).subscribe(
(data) => {
if (!path(['FundId'], data)) {
console.warn('$$$ FundId wasn\'t returned from server, doing logout...', data);
return this.logout();
}
this.updateUserSignupData(data, true);
},
(error) => {
if (toString(error['status']) === '403') { // usuário já existe
try {
if (typeof error['error'] === 'string') {
error['error'] = JSON.parse(error['error']);
}
this.updateUserSignupData(error['error'], false);
} catch (e) {
this.logout();
console.warn(e);
}
} else {
this.authStatus.next({...authStatusDefault, error: {...error, error_description: 'signup failure'}});
}
}
);
}
private handleSocket() {
if (!this.subscriptions['wsToken']) {
this.subscriptions['wsToken'] = this.store.select(UserDataSelectors.selectFeatureUserToken).pipe(
filter(token => !!token)
).subscribe(token => this.socketService.autenticate(token, { forceNew: true }, () => {
const fundId = this.loginService.getFundID();
this.socketService.emit('subscribe', fundId);
}));
}
if (!this.subscriptions['ws']) {
this.subscriptions['ws'] = this.socketEventService.getWSActivityObserver().subscribe((data: any) => {
if (data !== true) {
return;
}
this.changeAuthStatus('ws', true);
});
}
if (!this.subscriptions['wsError']) {
this.subscriptions['wsError'] = this.socketEventService.getSocketErrorObserver().subscribe((wsStatus) => {
if (!!wsStatus) {
LogService.loginStatusLog('$$$ wsError [doing logout]: ', wsStatus);
this.logout();
}
});
}
}
private handleLogin() {
this.loginService.loginUser().pipe(take(1)).subscribe(
(dt: any) => this.loginCompleted(dt),
(error: any) => {
try {
const dt = JSON.parse(error['error']);
dt['FundId'] = path(['FundId'], dt);
return this.loginCompleted(dt);
} catch (e) {
console.warn(e);
}
this.authStatus.next({...authStatusDefault, error: {...error, error_description: 'login failure'}});
}
);
}
private handleUserLogged() {
this.loginStatusService.updateStatus(LoginStatusEnum.UserLogged);
this.navigateToRoute();
}
private updateUserSignupData(data: any, firstLogin: boolean) {
this.store.dispatch(new UserDataActions.UserSetFundData(data));
this.setFundId(data['FundId']);
if (environment.unstableLogin) {
localStorage.setItem('ApiChecker', 'true');
}
this.firstLogin = firstLogin;
this.loggedFundType = data['FundTypeName'] || '';
if (this.firstLogin) {
AnalyticsService.setFirstLogin();
localStorage.setItem('first-login', 'true');
} else {
localStorage.removeItem('first-login');
}
this.changeAuthStatus('signup', true);
}
private loginCompleted(data) {
if (data) {
this.store.dispatch(new UserDataActions.UserSetFundData(data));
this.loggedFundType = data['FundTypeName'];
}
this.setFundId(data['FundId']);
localStorage.setItem('ApiChecker', 'true');
this.changeAuthStatus('login', true);
}
private loginFromStorage() {
const token = this.getAuthToken();
const authResult = !!token ? this.jwtHelper.decodeToken(token) : null;
if (!!authResult) {
this.onAutenticate(authResult, token);
return true;
}
return false;
}
private loginByUrl() {
try {
const p = UtilsService.getParameters();
if (p['first']) {
CookieService.setCookie('first_login', 1);
}
if (p['id_token']) {
const token_type = p['token_type'] || 'Bearer ';
const token = token_type + p['id_token'];
const authResult = this.jwtHelper.decodeToken(token);
this.onAutenticate(authResult, p['id_token']);
return true;
}
return false;
} catch (e) {}
}
private onAutenticate(authResult: any, idToken: string) {
// starting store
this.store.dispatch(new UserDataActions.UserLogin());
this.store.dispatch(new UserDataActions.UserSetAuthData(authResult, idToken));
// calling services
this.updateAnalytics(authResult);
// changing status
this.authStatus.next({...this.authStatus.getValue(), auth0: true, error: null});
this.loginStatusService.updateStatus(LoginStatusEnum.ConnectingWithServices);
}
private changeAuthStatus(key: string, value: boolean) {
this.authStatus.next({...this.authStatus.getValue(), [key]: value});
}
private runMock() {
if (!this.isMocked()) {
return false;
}
console.warn('$$$ Running mocked services!');
this.authenticationCompleted(MockedUser, MockedIdToken);
this.updateUserSignupData({...MockedUser, FundId: MockedUser.user_id}, false);
this.authStatus.next({error: null, login: true, signup: true, ws: true, auth0: true});
this.handleUserLogged();
return true;
}
private isMocked() {
return !environment.production && !!environment.enableMockedData;
}
private updateAnalytics(authResult?: any) {
const update = user_login => {
AnalyticsService.setUser(user_login);
AnalyticsService.setEvent('login', { loginType: 'user_login' });
};
if (authResult) {
return update(authResult['user_id']);
}
this.store.select(UserDataSelectors.selectFeatureUser).pipe(take(1)).subscribe(user => {
if (!!path(['user_id'], user)) {
update(user['user_id']);
}
});
}
private getAuthToken() {
// Check if there's an unexpired JWT
// It searches for an item in localStorage with key == 'id_token'
return this.jwtHelper.tokenGetter();
}
private logoutDone() {
try {
this.loggedFundType = null;
this.loginService.resetFundID();
this.loginStatusService.updateStatus(LoginStatusEnum.Auth0NotLogged, { needLocker: 1 });
this.authStatus.next(authStatusDefault);
this.router.navigateByUrl('/');
this.clearSubscriptions();
} catch (e) {
console.warn(e);
}
}
private clearSubscriptions() {
for (const s in this.subscriptions) {
if (!!this.subscriptions[s] && !this.subscriptions[s].closed) {
this.subscriptions[s].unsubscribe();
}
}
this.subscriptions = {};
}
private navigateToRoute() {
const isAdvisor = this.loggedFundType === 'ADVISOR';
if (isAdvisor) {
return this.router.navigate([`app/${ManagerRoutePath}`]);
}
if (this.firstLogin) {
if (!this.trustedSource()) {
return this.router.navigateByUrl('tutorial');
}
this.store.dispatch(new UserDataActions.UserSaveData({ source: this.source }));
}
const route = localStorage.getItem('lastroute');
if (!!route) {
return this.router.navigateByUrl((route.indexOf('tutorial') !== -1) ? 'tutorial' : route);
}
this.router.navigateByUrl('./app/resumo');
}
private trustedSource(): boolean {
return !!AppConstants.SourceWhitelist.find(source => source === this.source);
}
private setFundId(fundId) {
if (!!fundId) {
this.loginService.setFundId(fundId);
this.store.dispatch(new UserDataActions.UserSetCurrentFund(fundId));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment