When I try to use canActivate on a route it always returns false. I am doing an implicit flow and when it redirects back it seems like it does not wait for the service to be aware of the login and it always redirects back to the login page.
`@Injectable()
export class AuthGuardService implements CanActivate {
constructor (
private _oauthService: OAuthService,
private _router: Router
) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (this.loggedIn) {
return true;
}
//Redirect the user before denying them access to this route
this._router.navigate(['/welcome']);
return false;
}
get loggedIn() {
return this._oauthService.hasValidAccessToken();
}
}`
You are invoking oauthService.tryLogin({}), aren't you? (see Readme for more info)
Here's what I've used successfully:
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
import { OAuthService } from 'angular-oauth2-oidc';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private oauthService: OAuthService, private router: Router) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
if (this.oauthService.hasValidIdToken()) {
return true;
}
this.router.navigate(['/home']);
return false;
}
}
Same problem. Yes we are calling tryLogin() inside the loadDiscoveryDocument() resolve step.
However guards for the route seem to be invoked before tryLogin gets a chance to capture the auth tokens from the url. forever redirecting back to home.
I have a very similar issue (#76) as you describe, what ended up being wrong for me what the redirectUrl. For some reason, it didn't work with just using this.oAuthService.redirectUri = window.location.origin;, I had to concatenate index.html to the end of the location origin: this.oAuthService.redirectUri = window.location.origin + '/index.html';.
Hope this helps.
@Gimly: I don't think that's related at all.
@CrescentFresh The symptoms were similar, that's why I said that.
How does your redirect url look like (including params?)
Try to output your routes with
export const routing = RouterModule.forRoot(routes, {
useHash: true,
enableTracing: true, // <- debug the routes
initialNavigation: false // <- turn off the initial redirect, used for redirect or hash routing strategy
});
I have got the same effect to have an own login service that wrappes the oauthservice, but it turned out i got a loop in routes definition wth the canActivate method. Thus, tryLogin() was never executed in app.component.ts.
Double check your _storage (sessionStorage/localStorage) to see if there are tokens stored or exist. If oidc is used and id token shall be provided, also double check that the issuer is provided. If the id token doesn't pass the issuer check, the access token will not be passed either.
@manfredsteyer: this library is the most best third-part angular2 lib i can found. I can confirm it works very well with google open id connect and oauth2 while using angular 2.4.10 and hashLocation strategy.
thanks @yingding
I think the problem is related to when it is the '' (root) route being matched (or at least on the first load for the UI) where regular implementations call the asynchronous loadDiscoveryDocumentAndTryLogin() method in some AppComponent constructor. The Angular request lifecycle gets at the GuardsCheck* events before the discovery document is returned and the TryLogin part can be executed.
Besides bedag-moo's comment (I wasn't able to call execute the TryLogin() method in theCanActivatemethod) you can return anObservable` in the guard like so:
canActivate(): Observable<boolean> { return fromPromise(this.auth.loadDiscoveryDocumentAndTryLogin()).map(() => { if(this.auth.hasValidIdToken()) { //or AccessToken console.log('authenticated'); return true; } console.log('not authenticated'); this.auth.initImplicitFlow(); return false; }); }
Had similar issue. Thanks to yingding's answer above, all I needed was export const routing = RouterModule.forRoot(routes, {
initialNavigation: false // <- turn off the initial redirect, used for redirect or hash routing strategy
});
In case anyone else runs into this, I started with disabling 'initialNavigation' per the above comments.
export const routing = RouterModule.forRoot(routes, {
initialNavigation: false // <- turn off the initial redirect, used for redirect or hash routing strategy
});
Then, I found the best approach is to trigger the router navigation immediately after the login attempt using the following (which also implements passing the state parameter).
this.oauthService.loadDiscoveryDocumentAndTryLogin({
onTokenReceived: (info) => {
if (info.state) this.router.navigate([info.state]);
}
}).then(
info => this.router.initialNavigation()
);
In case anyone else runs into this, I started with disabling 'initialNavigation' per the above comments.
export const routing = RouterModule.forRoot(routes, { initialNavigation: false // <- turn off the initial redirect, used for redirect or hash routing strategy });Then, I found the best approach is to trigger the router navigation immediately after the login attempt using the following (which also implements passing the state parameter).
this.oauthService.loadDiscoveryDocumentAndTryLogin({ onTokenReceived: (info) => { if (info.state) this.router.navigate([info.state]); } }).then( info => this.router.initialNavigation() );
This worked for me also, thanks @seandevenish
@seandevenish Thanks for the suggestion. you saved my time :)
Most helpful comment
In case anyone else runs into this, I started with disabling 'initialNavigation' per the above comments.
Then, I found the best approach is to trigger the router navigation immediately after the login attempt using the following (which also implements passing the state parameter).