keycloak-angular
keycloak-angular copied to clipboard
Completely exclude some routes from keycloak
- [ ] bug report -> please search for issues before submitting
- [x] feature request
Versions.
6.0.1
Desired functionality.
I have a router with several endpoints. Keycloak service is initialised in root app module with APP_INITIALIZER as described in manual. During the initialization process, keycloak performs redirect to sso page and back. What I need: do NOT perform keycloak initialization and any redirections for some routes at all. How can I achieve this for now?
Hi, instead of using the APP_INITIALIZER for the entire app, you should use Guards (for example CanLoad on a lazy loaded module) to add the keyCloak logic.
There is also a talk in this thread: https://github.com/mauriciovigolo/keycloak-angular/issues/117
@weihsth I have a similar question, could your give more detail description. thanks!
I wanted to ask the same question, so is there any suggestions @mauriciovigolo regarding this?
To be more accurate, we want routes like '/about', '/signup' publicly accessible. If we exclude mentioned paths from bearerInterceptor, users are still redirected to KC login. If we disable bearer interceptor, than we have manual control using guards and interceptors, but we are not sure is that good way.
We are tried to initialize KeycloakService during app initialization like this:
await keycloak.init({
config: environment.keycloakConfig,
loadUserProfileAtStartUp: false,
initOptions: {
onLoad: 'check-sso',
checkLoginIframe: false
},
bearerExcludedUrls: ['/about','/signup'],
bearerPrefix: 'KC-Bearer'
});
Except initial approach (by disabling bearerInterceptor), we could place all private routes under private module and initialize Keycloak there as weihsth suggested.
Hi @dsarcevic. Are you using an implementation similar to https://github.com/mauriciovigolo/keycloak-angular#authguard?
That example doesn't check if the route is public or not and redirects to the login page if the user is not authenticated.
if (!this.authenticated) {
this.keycloakAngular.login()
resolve(false);
return;
}
One thing you could do is to retrieve the excludedUrls from KeycloakService and check if the current route is public or not, avoiding to call the login method in those cases.
In the newer version (8.0.0), I will completely rewrite this logic and make it easier to handle, but we will have breaking changes.
Feel free to contact me if you need any other help.
Hi @mauriciovigolo , We tried to implement guard which would allow that users without authentication can access to public urls (and not access to protected pages), but if we initialize Keycloak instance as I copied above (using initializer function in app.module), guard is ignored and users are always redirected to Keycloak login.
As I said, if we disable bearerInterceptor and manually put Bearer in header on places where user is authenticated, than we can achieve desired behaviour, but we are not sure is that good approach.
Do you have any idea when we can expect 8.0.0?
p.s. Many thanks for great library
Hi @mauriciovigolo , We tried to implement guard which would allow that users without authentication can access to public urls (and not access to protected pages), but if we initialize Keycloak instance as I copied above (using initializer function in app.module), guard is ignored and users are always redirected to Keycloak login.
As I said, if we disable bearerInterceptor and manually put Bearer in header on places where user is authenticated, than we can achieve desired behaviour, but we are not sure is that good approach.
Do you have any idea when we can expect 8.0.0?
p.s. Many thanks for great library
Hi @mauriciovigolo
Any updates on this? I am facing similar blocker issue for my angular app
Hi @mauriciovigolo
Any updates on this? I am facing similar blocker issue for my angular app
Same here! Hope you're all well!
+1 to help motivate for a higher priority of this feature.
Having said that if somebody could provide a more detailed working example that would go a long way.
The working example is really quite simple.
In your AppModule (or wherever the route is, that requires a login) you need to add a canLoad
-Guard, that initializes your Keycloak-Instance. In theory it is possible to use a canActivate
-Guard but this can lead to an infinite redirect loop.
app.module.ts:
const routes: Routes = [
{
path: '/private',
loadChildren: () =>
import('./private/private.module').then(m => m.PrivateModule),
canLoad: [IsAuthorizedGuard],
},
// ... other public routes
]
@NgModule({
imports: [
BrowserModule,
FormsModule,
RouterModule.forRoot(routes),
KeycloakAngularModule,
],
providers: [
KeycloakService
],
declarations: [ AppComponent, HelloComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
is-authorized.guard.ts
@Injectable({
providedIn: 'root'
})
export class IsAuthorizedGuard implements CanLoad {
constructor(private readonly keycloakService: KeycloakService) {}
canLoad(route: Route, segments: UrlSegment[]): Observable<boolean> {
return this.keycloakService.init(
// your config
).then(this.keycloakService.isLoggedIn());
}
}
Another problem that occured was, that requests requiring a logged in user performed at startup were no longer possible. For example requests, that load additional information about the logged in user. This can be solved by listening for the OnReady
-Event. (args is true if the login was successful)
this.keycloakService.keycloakEvents$
.pipe(
filter(({ type, args }) => type === KeycloakEventType.OnReady && args),
first(),
switchMap(() => this.http.get<User>('/api/user')),
)
.subscribe(user => {
// do something with the user object
});
I hope this helps! :)
@hesch
canLoad(route: Route, segments: UrlSegment[]): Observable<boolean> {
return this.keycloakService.init(
// your config
).then(this.keycloakService.isLoggedIn());
}
-
I presume it should be
this.keycloakService.isLoggedIn
instead ofthis.keycloakService.isLoggedIn()
. -
When I add the
this.keycloakService.isLoggedIn
part, then the app just redirects back to\
without doing anything but if I take it out and just have:return this.keycloakService.init(config)
then it redirects as expected. Problem is then according to the rest of the application Keycloak isn't initialized.
Any ideas?
@hesch
Thank you so much for your example, I got it working.
My is-authorized.guard.ts needed to change to:
canLoad(route: Route, segments: UrlSegment[]): Promise<boolean> {
return this.keycloakService.init(keycloakOptions);
}
Another bit that missing was to add the interceptor to my private module as per #180 :
...
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: KeycloakBearerInterceptor,
multi: true
}
],
...
I didn't run into the scenario where I had to use the keycloakEvents
.
+1
Is same can achievable for nodejs + express app for
/login route
/contactUs
for the time being i'm achieving this like : 1- fetch token first app.use('/api/login', generateKeyCloakToken);
2- then init the keycloak middleware instance app.use(keycloak.middleware());
Thanks