Maximum call stack size exceeded at Array.map in Login component
See original GitHub issueIssue type
I’m submitting an issue when I made login (check one with “x”)
- [x ] bug report
- feature request
- question about the decisions made in the repository
Issue description
when I try to make login using the authentication component. The screen is keeping freezer and no any request is made to the backend. when I try many times in the console appear the following error Maximum call stack size exceeded"
Current behavior:
i have the configuration of authentication using jwt token
Expected behavior:
the ngx-admin must be working using jwt token sending the authorization bearer header to the backend and even update the token when it is revoked.
Steps to reproduce:
- I used
Related code:
app.module.ts
`/**
- @license
- Copyright Akveo. All Rights Reserved.
- Licensed under the MIT License. See License.txt in the project root for license information. */ import { BrowserModule } from ‘@angular/platform-browser’; import { BrowserAnimationsModule } from ‘@angular/platform-browser/animations’; import { NgModule, ErrorHandler } from ‘@angular/core’; import { HttpClientModule, HTTP_INTERCEPTORS } from ‘@angular/common/http’; import { CoreModule } from ‘./@core/core.module’; import { ThemeModule } from ‘./@theme/theme.module’; import { AppComponent } from ‘./app.component’; import { AppRoutingModule } from ‘./app-routing.module’; import { NbPasswordAuthStrategy, NbAuthModule, NbAuthJWTToken, NbAuthJWTInterceptor, NbTokenStorage, NbTokenLocalStorage, NB_AUTH_TOKEN_INTERCEPTOR_FILTER } from ‘@nebular/auth’; import {AuthModule} from ‘./auth/auth.module’; import { NbSecurityModule, NbRoleProvider } from ‘@nebular/security’; import { environment } from ‘…/environments/environment’; import { NbChatModule, NbDatepickerModule, NbDialogModule, NbMenuModule, NbSidebarModule, NbToastrModule, NbWindowModule, } from ‘@nebular/theme’; import { AuthGuard } from ‘./auth-guard.service’; import {RoleProvider} from ‘./role.provider’; import { GlobalErrorHandler } from ‘./global-error-handler’; import { ServerErrorInterceptor } from ‘./server-error.interceptor’; @NgModule({ declarations: [AppComponent], imports: [ BrowserModule, BrowserAnimationsModule, HttpClientModule, AppRoutingModule, ThemeModule.forRoot(), NbSidebarModule.forRoot(), NbMenuModule.forRoot(), NbDatepickerModule.forRoot(), NbDialogModule.forRoot(), NbWindowModule.forRoot(), NbToastrModule.forRoot(), NbSecurityModule.forRoot(), NbChatModule.forRoot({ messageGoogleMapKey: ‘AIzaSyA_wNuCzia92MAmdLRzmqitRGvCF7wCZPY’, }), CoreModule.forRoot(), AuthModule, NbAuthModule.forRoot({ strategies: [ NbPasswordAuthStrategy.setup({ name: ‘email’, baseEndpoint: environment.baseUrlApi, token: { class: NbAuthJWTToken, key: ‘token’, // this parameter tells where to look for the token }, login: { endpoint: ‘/users/login’, method: ‘post’, redirect: { success: ‘/page/’, failure: null, // stay on the same page }, }, register: { endpoint: ‘/users/sign-in’, method: ‘post’, }, }), ], forms: {}, }),
], providers: [ AuthGuard, { provide: NbRoleProvider, useClass: RoleProvider }, { provide: ErrorHandler, useClass: GlobalErrorHandler }, { provide: NbTokenStorage, useClass: NbTokenLocalStorage }, { provide: HTTP_INTERCEPTORS, useClass: NbAuthJWTInterceptor, multi: true }, { provide: NB_AUTH_TOKEN_INTERCEPTOR_FILTER, useValue: (req) => { return false }}, { provide: HTTP_INTERCEPTORS, useClass: ServerErrorInterceptor, multi: true }, ], bootstrap: [AppComponent], }) export class AppModule { } `
app-routing.module.ts
`import { ExtraOptions, RouterModule, Routes } from ‘@angular/router’; import { NgModule } from ‘@angular/core’; import {LoginComponent} from ‘./auth/components/login/login.component’; import { AuthGuard } from ‘./auth-guard.service’; import { NbAuthComponent, NbLoginComponent, NbLogoutComponent, NbRegisterComponent, NbRequestPasswordComponent, NbResetPasswordComponent, } from ‘@nebular/auth’;
export const routes: Routes = [ { path: ‘pages’, canActivate: [AuthGuard], // here we tell Angular to check the access with our AuthGuard loadChildren: () => import(‘./pages/pages.module’) .then(m => m.PagesModule), }, { path: ‘auth’, component: NbAuthComponent, children: [ { path: ‘’, component: LoginComponent, }, { path: ‘login’, component: LoginComponent, }, { path: ‘register’, component: NbRegisterComponent, }, { path: ‘logout’, component: NbLogoutComponent, }, { path: ‘request-password’, component: NbRequestPasswordComponent, }, { path: ‘reset-password’, component: NbResetPasswordComponent, }, ], }, { path: ‘’, redirectTo: ‘pages’, pathMatch: ‘full’ }, { path: ‘**’, redirectTo: ‘pages’ }, ];
const config: ExtraOptions = { useHash: false, };
@NgModule({ imports: [RouterModule.forRoot(routes, config)], exports: [RouterModule], }) export class AppRoutingModule { } `
auth-guard.service.ts `import { Injectable } from ‘@angular/core’; import { CanActivate, Router } from ‘@angular/router’; import { NbAuthService } from ‘@nebular/auth’; import { tap } from ‘rxjs/operators’;
@Injectable() export class AuthGuard implements CanActivate {
constructor(private authService: NbAuthService, private router: Router) { }
canActivate() { return this.authService.isAuthenticated() .pipe( tap(authenticated => { if (!authenticated) { this.router.navigate([‘auth/login’]); } }), ); } }`
global-error-handler.ts `import { Injectable } from ‘@angular/core’; import { CanActivate, Router } from ‘@angular/router’; import { NbAuthService } from ‘@nebular/auth’; import { tap } from ‘rxjs/operators’;
@Injectable() export class AuthGuard implements CanActivate {
constructor(private authService: NbAuthService, private router: Router) { }
canActivate() { return this.authService.isAuthenticated() .pipe( tap(authenticated => { if (!authenticated) { this.router.navigate([‘auth/login’]); } }), ); } }`
global-error-handler.ts ` import { ErrorHandler, Injectable, Injector } from ‘@angular/core’; import { HttpErrorResponse } from ‘@angular/common/http’; import { ErrorService } from ‘./@core/services/error.service’; import { LoggingService } from ‘./@core/services/logging.service’; import { NotificationService } from ‘./@core/services/notification.service’;
@Injectable() export class GlobalErrorHandler implements ErrorHandler {
constructor(private injector: Injector) { }
handleError(error: Error | HttpErrorResponse) { const errorService = this.injector.get(ErrorService); const logger = this.injector.get(LoggingService); const notifier = this.injector.get(NotificationService); let message; let stackTrace; if (error instanceof HttpErrorResponse) { // Server error message = errorService.getServerErrorMessage(error); stackTrace = errorService.getServerErrorStackTrace(error); notifier.showError(message); } else { // Client Error message = errorService.getClientErrorMessage(error); notifier.showError(message); } // Always log errors logger.logError(message, stackTrace); console.error(error); } }`
server-error.interceptor.ts `import { Injectable, Injector } from ‘@angular/core’; import { HttpEvent, HttpRequest, HttpHandler, HttpInterceptor, HttpErrorResponse, } from ‘@angular/common/http’; import { Observable, throwError } from ‘rxjs’; import { retry, catchError } from ‘rxjs/operators’; import { Router } from ‘@angular/router’; import { NotificationService } from ‘./@core/services/notification.service’;
@Injectable() export class ServerErrorInterceptor implements HttpInterceptor { constructor(private injector: Injector) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(
retry(1),
catchError((error: HttpErrorResponse) => {
let errorMsg;
if (error.error instanceof Error) {
// A client-side or network error occurred. Handle it accordingly.
errorMsg = 'An error occurred: ${error.error.message}';
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
errorMsg = 'Backend returned code ${error.status}, body was: ${error.error}';
}
if (error.status === 401 || error.status === 403) {
this.injector.get(NotificationService).showUnathorized(errorMsg);
this.injector.get(Router).navigateByUrl('/auth/login');
} else {
return throwError(error);
}
})
);
} }`
insert short code snippets here
Other information:
npm, node, OS, Browser
<!--
Node, npm: `node --version` and `npm --version`
OS: Windows (7/8/10). Linux (incl. distribution). macOS (El Capitan? Sierra?)
Browser: Chrome/Safari/Firefox/etc?
-->
Angular, Nebular
<!--
Check your `package-lock.json` or locate a `package.json` in the `node_modules` folder.
-->
`{
"name": "crm-app",
"version": "4.0.1",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/akveo/ngx-admin.git"
},
"bugs": {
"url": "https://github.com/akveo/ngx-admin/issues"
},
"scripts": {
"ng": "ng",
"conventional-changelog": "conventional-changelog",
"start": "ng serve --host 0.0.0.0",
"build": "ng build",
"build:prod": "npm run build -- --prod --aot",
"test": "ng test",
"test:coverage": "rimraf coverage && npm run test -- --code-coverage",
"lint": "ng lint",
"lint:fix": "ng lint crm-app --fix",
"lint:styles": "stylelint ./src/**/*.scss",
"lint:ci": "npm run lint && npm run lint:styles",
"pree2e": "webdriver-manager update --standalone false --gecko false",
"e2e": "ng e2e",
"docs": "compodoc -p src/tsconfig.app.json -d docs",
"docs:serve": "compodoc -p src/tsconfig.app.json -d docs -s",
"prepush": "npm run lint:ci",
"release:changelog": "npm run conventional-changelog -- -p angular -i CHANGELOG.md -s",
"postinstall": "ngcc --properties es2015 es5 browser module main --first-only --create-ivy-entry-points"
},
"dependencies": {
"@akveo/ng2-completer": "^9.0.1",
"@angular/animations": "^9.0.4",
"@angular/cdk": "^9.1.2",
"@angular/common": "^9.0.4",
"@angular/compiler": "^9.0.4",
"@angular/core": "^9.0.4",
"@angular/forms": "^9.0.4",
"@angular/material": "^9.1.0",
"@angular/platform-browser": "^9.0.4",
"@angular/platform-browser-dynamic": "^9.0.4",
"@angular/router": "^9.0.4",
"@asymmetrik/ngx-leaflet": "3.0.1",
"@nebular/auth": "5.0.0",
"@nebular/eva-icons": "5.0.0",
"@nebular/security": "^5.0.0",
"@nebular/theme": "5.0.0",
"@swimlane/ngx-charts": "^13.0.2",
"angular2-chartjs": "0.4.1",
"bootstrap": "4.3.1",
"chart.js": "^2.7.1",
"ckeditor": "4.7.3",
"classlist.js": "1.1.20150312",
"core-js": "2.5.1",
"echarts": "^4.0.2",
"eva-icons": "^1.1.3",
"intl": "1.2.5",
"ionicons": "2.0.1",
"leaflet": "1.2.0",
"nebular-icons": "1.1.0",
"ng2-charts": "^2.3.2",
"ng2-ckeditor": "^1.2.2",
"ng2-smart-table": "^1.6.0",
"ngx-echarts": "^4.2.2",
"node-sass": "^4.12.0",
"normalize.css": "6.0.0",
"pace-js": "1.0.2",
"roboto-fontface": "0.8.0",
"rxjs": "6.5.4",
"rxjs-compat": "6.3.0",
"socicon": "3.0.5",
"style-loader": "^1.1.3",
"tinymce": "4.5.7",
"tslib": "^1.10.0",
"typeface-exo": "0.0.22",
"web-animations-js": "^2.3.2",
"zone.js": "~0.10.2"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.900.4",
"@angular/cli": "^9.0.4",
"@angular/compiler-cli": "^9.0.4",
"@angular/language-service": "9.0.4",
"@compodoc/compodoc": "1.0.1",
"@fortawesome/fontawesome-free": "^5.2.0",
"@types/d3-color": "1.0.5",
"@types/jasmine": "2.5.54",
"@types/jasminewd2": "2.0.3",
"@types/leaflet": "1.2.3",
"@types/node": "^12.11.1",
"codelyzer": "^5.1.2",
"conventional-changelog-cli": "1.3.4",
"jasmine-core": "2.6.4",
"jasmine-spec-reporter": "4.1.1",
"karma": "1.7.1",
"karma-chrome-launcher": "2.1.1",
"karma-cli": "1.0.1",
"karma-coverage-istanbul-reporter": "1.3.0",
"karma-jasmine": "1.1.0",
"karma-jasmine-html-reporter": "0.2.2",
"npm-run-all": "4.0.2",
"protractor": "5.1.2",
"rimraf": "2.6.1",
"stylelint": "7.13.0",
"ts-node": "3.2.2",
"tslint": "^5.7.0",
"tslint-language-service": "^0.9.9",
"typescript": "3.7.5",
"yargs": "^15.4.0"
}
}
`
Issue Analytics
- State:
- Created 3 years ago
- Reactions:4
- Comments:12
Top GitHub Comments
I found a possible solution, apparently if you takes too long the log again on the login strategy that you are using, and tries to login without already been properly logged out the nebular will somehow get in a infinite loop, for exemple, when the token still present in the browser local storage if you are using the localStorageStrategy for token storage and tries to login.
that’s explain why the login works in other browsers (that you haven’t logged before) and also works in incognito mode.
The solution cab be achieved by extending the NbLoginComponent, then getting access to the NbTokenStorage by dependency injection and clearing the token before the login happens
e.g:
A temporary solution is to clear the site data in Developer Tools > Application