7

I am using angular CanActivate Authguard interface to protect my component.

@Injectable()
export class AuthGuard implements CanActivate{

constructor(private router: Router, private authService: AuthenticationService) {}

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

    this.authService.isLoggedIn.take(1).map((isLoggedIn : boolean) => {

        if(!isLoggedIn){
            this.router.navigate(['/login']);
            return false;
        }

        return true;
    })

    this.router.navigate(['/login']);
    return false;
   }
}

i added it to my router configuration like this.

const appRoutes: Routes = [
{path : '',redirectTo : 'login',pathMatch : 'full'},
{ path: 'home', component: HomeComponent,canActivate : [AuthGuard] }
]

I also added it to providers array.

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
providers: [AuthGuard,  
ExpenseService,SellDetailService,AuthenticationService],
styleUrls: ['./app.component.css']
})

But when i run the application its giving following error

StaticInjectorError(AppModule)[AuthGuard]:
StaticInjectorError(Platform: core)[AuthGuard]: NullInjectorError: No provider for AuthGuard!

I think i implemented it courrectly but its not working . what i am doing wrong???

Fateme Fazli
  • 11,582
  • 2
  • 31
  • 48
user3692033
  • 585
  • 3
  • 8
  • 21
  • try adding it to providers of main module – Dhyey May 19 '18 at 07:01
  • you need to add it to `providers` section of the module in which you use routes config where your guard is used – dee zg May 19 '18 at 07:03
  • 1
    Another issue ( not related with error ) is that `authService.isLoggedIn` is async so the lines after it will be executed immediately. So it will always redirect to login – Dhyey May 19 '18 at 07:03
  • 1
    It needs to be added to the providers array of your module, not your component – user184994 May 19 '18 at 07:05
  • I've detailed out an answer providing why you're seeing the error you're seeing as well as options available to you as a solution :) if you have any further issues related to this question or have additional questions ask away! good luck and happy coding! – Jessy Apr 24 '20 at 14:28

6 Answers6

39

You should add name of your guards to app.module in providers array Something like this

Providers:[AuthGuard]

Stefan Morcodeanu
  • 2,108
  • 1
  • 11
  • 17
  • I don't believe that is necessary, is it? – Sal Sep 27 '18 at 20:14
  • 1
    I was having this same problem, and while from everything I read says this shouldn't be required, it worked. – chubbsondubs Jan 07 '19 at 02:20
  • It's only necessary if it's not provided in some kind of shared module OR if the providedIn: 'root' is not added to the Injectable decorator of the guard. By default, the CLI doesn't add it so you have to choose how it will be provided throughout your application. – Jessy Apr 24 '20 at 14:30
5

You need to include AuthGuard to the provider's array in app.module.ts

import { AuthGuard } from './_guards/auth.guard'; //<-------

@NgModule({
  declarations: [
    AppComponent,
    NavComponent,
    LoginComponent,   
  ],
  imports: [   
    MatTableModule,
    EditorModule,    
  ],
  providers: [    
    AuthGuard, // <------------ Include here
    ProfileResolver    
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}
Supun Praneeth
  • 3,087
  • 2
  • 30
  • 33
Malith
  • 506
  • 5
  • 9
4

Add following in your app.module.ts file:

providers: [ AuthGuard ]

Sani
  • 81
  • 4
4

The issue you're seeing is AuthGuard is being provided in your component however, it needs to be provided at a higher level. In your case the routing module. The staticInjector error is letting you know that Angular can't find the AuthGuard.

As others have mentioned you have two solutions available to you.

Option 1:

Provide your AuthGuard in the app module OR another module that you share between modules. as an example, it may look something like this.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AuthGuard } from 'src/app/core/auth.guard';

@NgModule({
  imports: [
    BrowserModule,
    AppRoutingModule,
  ],
  declarations: [
    AppComponent,
  ],
  providers: [
    AuthGuard // ADDED so AuthGuard can be accessed in any routing module.
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Option 2

This is my preferred approach for AuthGuard's as they're most likely a singleton. You'll simply need to add to the @Injectable() decorator { providedIn: 'root' }. This looks something like:

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

@Injectable({
  providedIn: 'root' // ADDED providedIn root here.
})
export class AuthGuard implements CanActivate {


  constructor() { }

  canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    return true; // AUTH LOGIC HERE.
  }

}

Tip: You'll notice if you generate Services from the CLI it'll have the { providedIn: 'root' } but creating a Guard won't.

Jessy
  • 1,150
  • 16
  • 27
3

Add: { providedIn: 'root' } inside the @Injectable() in AuthGuard

2

You should add AuthGuard to app.module in providers

Providers:[AuthGuard]

app.module

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AuthGuard } from 'src/app/core/auth.guard';

@NgModule({
  imports: [
    BrowserModule,
    AppRoutingModule,
  ],
  declarations: [
    AppComponent,
  ],
  providers: [AuthGuard], // Add AuthGuard here
  bootstrap: [AppComponent]
})
export class AppModule { }
Akitha_MJ
  • 3,882
  • 25
  • 20