Angular Error: Attempting to access property 'then' of undefined object causes TypeError

I am struggling with implementing JHipster Auth-guard. I am facing an issue where canActivate is not triggered for a user without permission for a specific route.

I have carefully examined my code, but the console shows that .then() is undefined at the specified line. I even checked the principal through console logging and it appears to be defined. Can anyone in the Stack Overflow community help me identify what I might be doing wrong?

checkLogin(authorities: string[], url: string): Promise<boolean> {
    var principal = this.principal;

    return Promise.resolve(principal.identity().then((account) => {



   ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'then' of undefined
TypeError: Cannot read property 'then' of undefined
    at AuthGuard.checkLogin (auth-guard.ts:27)
    at AuthGuard.canActivate (auth-guard.ts:21)

This is how my code looks:

app.module

    const routes: Routes = [
    {
        path: '**',
        component: DashboardComponent,
        canActivate: [AuthGuard],
        resolve: {
            data: DashboardService
        }
    }
];

@NgModule({
    declarations: [
        DashboardComponent
    ],
    imports: [
        RouterModule.forChild(routes),
        HttpClientModule,
        HttpModule,
        CdkTableModule,
        MatButtonModule,
        MatDividerModule,
        MatFormFieldModule,
        MatIconModule,
        MatMenuModule,
        MatSelectModule,
        MatSidenavModule,
        MatTableModule,
        MatTabsModule,

        NgxChartsModule,
    ],
    providers: [
        ProjectDashboardService, AuthGuard, Principal, StateStorageService
    ]
})

Auth-guard.ts

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';

import { Principal } from './principal.service';
import { StateStorageService } from './state-storage.service';

@Injectable()
export class AuthGuard implements CanActivate {

    constructor(private router: Router,
        private principal: Principal,
        private stateStorageService: StateStorageService) {
    }

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Promise<boolean> {

        const authorities = route.data['authorities'];
        // It's important to call checkLogin / and thus the principal.identity() function, to ensure that the client also has a principal if they were previously logged in by the server. This could happen on a page refresh.
        
        return this.checkLogin(authorities, state.url);
    }

    checkLogin(authorities: string[], url: string): Promise<boolean> {
        var principal = this.principal;

        return Promise.resolve(principal.identity().then((account) => {

            if (!authorities || authorities.length === 0) {
                return true;
            }

            if (account) {
                return principal.hasAnyAuthority(authorities).then((response) => {
                    if (response) {
                        return true;
                    }
                    return false;
                });
            }

            this.stateStorageService.storeUrl(url);
            window.location.href = "http://stackoverflow.com";
            return false;
        }));
    }
}

principal service.ts

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';


@Injectable()
export class Principal {
    private userIdentity: any;
    private authenticated = false;
    private authenticationState = new Subject<any>();

    constructor(

    ) { }

    authenticate(identity) {
        this.userIdentity = identity;
        this.authenticated = identity !== null;
        this.authenticationState.next(this.userIdentity);
    }

    hasAnyAuthority(authorities: string[]): Promise<boolean> {
        return Promise.resolve(this.hasAnyAuthorityDirect(authorities));
    }

    hasAnyAuthorityDirect(authorities: string[]): boolean {
        if (!this.authenticated || !this.userIdentity || !this.userIdentity.authorities) {
            return false;
        }

        for (let i = 0; i < authorities.length; i++) {
            if (this.userIdentity.authorities.includes(authorities[i])) {
                return true;
            }
        }

        return false;
    }

    hasAuthority(authority: string): Promise<boolean> {
        if (!this.authenticated) {
            return Promise.resolve(false);
        }

        return this.identity().then((id) => {
            return Promise.resolve(id.authorities && id.authorities.includes(authority));
        }, () => {
            return Promise.resolve(false);
        });
    }

    identity(force?: boolean): Promise<any> {
        if (force === true) {
            this.userIdentity = undefined;
        }

        if (this.userIdentity) {
            return Promise.resolve(this.userIdentity);
        }

    }

    isAuthenticated(): boolean {
        return this.authenticated;
    }

    isIdentityResolved(): boolean {
        return this.userIdentity !== undefined;
    }

    getAuthenticationState(): Observable<any> {
        return this.authenticationState.asObservable();
    }

    getImageUrl(): String {
        return this.isIdentityResolved() ? this.userIdentity.imageUrl : null;
    }
}

Answer №1

Special thanks to @user184994 for the assistance. I found that the solution worked perfectly when I changed the return statement to false in

principal.identity()

This change ensures that it returns false if the userIdentity is false, and by removing this

if (!authorities || authorities.length === 0) { return true; }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Customizing the placeholder text for each mat input within a formArray

I have a specific scenario in my mat-table where I need to display three rows with different placeholder text in each row's column. For example, test1, test2, and test3. What would be the most efficient way to achieve this? Code Example: <div form ...

Is there a method to enable the acceptance of both dots and commas as decimal markers in input fields?

Hey there! I have a question for you. Is there a way to allow users to input both commas and dots as decimal markers, but still display the value with dots and remove thousand separators? For example, when a user inputs "123456,78", they should see "123 ...

When passing an invalid value to the Props in TypeScript, no errors are being thrown

const enum ColumnValues { one = 1, two = 2, three = 3, } interface Props { style?: StyleProp<ViewStyle>; title?: string; titleContainerStyle?: StyleProp<ViewStyle>; titleStyle?: StyleProp<TextStyle>; textInputStyle?: Styl ...

Passing a complex variable type in TypeScript to a function without the need to redefine the type

I'm fairly new to working with TypeScript and I've encountered this issue several times. When using tools like Prisma to retrieve data, I often come across values with incredibly complex types. These values contain many attributes, which is perf ...

Is the tooltip display for Typescript types in VSCode reliable? No need for unnecessary type assertions

Exploring the concept of const assertions in TypeScript Looking at the array allDeviceTypes depicted below, VSCode indicates it has a return type of string[] when hovering over the variable name. https://i.sstatic.net/gIYch.png However, upon using a con ...

Mastering the art of duplicating an array of objects in TypeScript

I attempted the following strategy: this.strategies = []; this.strategiesCopy = [...this.strategies]; Unfortunately, it appears this method is not effective as it results in duplicates. ...

Altering the dimensions of radio buttons

I am a newcomer to using material-ui. I am currently working on incorporating radio buttons in a component and would like to reduce its size. While inspecting it in Chrome, I was able to adjust the width of the svg icon (1em). However, I am unsure how to a ...

angular slickgrid grid date formatting only applies to grid view

this.columnDefinitions = [ { id: 'edit', field: 'id', excludeFromColumnPicker: true, excludeFromGridMenu: true, excludeFromHeaderMenu: true, formatter: Fo ...

Utilizing AWS CDK to Define StackProps Input Variables

Recently, I have started using the AWS CDK and encountered a challenge. I want to allow end users to define custom input variables when using my AWS CDK without having to edit the entire code. While I have been able to work with standard types such as stri ...

What distinguishes between a public variable declared as var: any = []; versus a public variable declared as var: any[] =

I'm seeking clarification on the distinction between the following: public var: any = []; // versus public var: any[] = []; ...

Definition file for mapbox-gl-draw in Typescript, also known as d.ts file

I attempted to define the mapbox-gl-draw project in a typed manner but unfortunately, I was unsuccessful. Can anyone provide some guidance on this? Here is how the javascript file looks: 'use strict'; var Setup = require('./src/setup&apos ...

Facing issues with Angular 13 migration: Schema validation encountered errors stating that the data path "/error" needs to be a string

Currently in the process of migrating from Angular 8 to 13 and encountering an issue. I have been following the guidelines outlined on https://update.angular.io/, however, every time I attempt to build certain custom libraries from my application root fold ...

Demystifying the Mechanics of RxJS Subscriptions during an HTTP Request

export class VendorHttpService { result = '0'; constructor(private http: HttpClient, private global: GlobalService) { } getProfileStatus(uid: String): string { this.http.get(this.global.getUrl()+"/vendor/profile-status/"+uid) ...

Error message: Material Design UI - The type 'string' cannot be assigned to the type Icon

I am currently working on a component that is responsible for returning the specific icon based on the prop that is passed. Here is a simplified version of how it works in my application: import * as icons from "@mui/icons-material"; interface I ...

Differentiating elements from two array objects in typescript: a guide

I am facing an issue in extracting the different elements from two array objects. Here is my example: array1 = [{id: 1, a: "a", b: "b"}, {id: 2, c: "c", d: "d"}, {id: 3, e: "e", f: "f"}]; array2 = ...

Angular reactive forms throwing ERROR TypeError: "Property blogTitle is not defined"

I have encountered a problem while attempting to develop a reactive form in Angular. Upon loading the page in the browser, two errors are displayed in the console: ERROR TypeError: "_co.createBlogForm.form is undefined" and ERROR TypeError: "_co.blogTitle ...

The ngModel feature is not functioning properly when trying to update in tag inputs

I am having trouble with two-way data binding using ngModel in tag-inputs. Can someone please assist me? Here is the link to my code on StackBlitz ...

Troubleshooting problem with Angular 2 in Internet Explorer related to the use of [style]="

I've encountered a challenge while using angular 2 (2.0.0-beta.17). The app works perfectly on most browsers, but as expected, IE 11 is causing trouble. The scripts included in the head for angular are: <script type='text/javascript' sr ...

Display an icon within an HTML element when the content inside it exceeds its boundaries

Looking to display a copy to clipboard icon when the content inside a div overflows I am using ngFor to iterate through four divs, and if any of those divs is overflowing, I want to show an icon specific to that respective div. <div *ngFor div of Four ...

What is the best way to output a JSX element using an inline switch statement?

I have been attempting to use an inline switch in order to return an element, but all I am getting is an empty <span> </span>. What could be the issue here? getRowTdForHeader: (header: string, entry: response) => { return (< ...