Is there a guide for using SSR with Angular 19 and provideKeycloak?
Bug Report or Feature Request (mark with an x)
- [ ] bug report -> please search for issues before submitting
- [x] feature request
Versions.
keycloak-angular 19
Repro steps.
The log given by the failure.
Desired functionality.
I'm working with Angular 19 and keycloak-angular for authentication. I'm trying to implement Server-Side Rendering (SSR) using Angular Universal, and I want to use the provideKeycloak provider for Keycloak authentication.
However, I'm unsure how to properly set up provideKeycloak in an SSR environment, as there are issues with accessing the window object and configuring the provider correctly.
What I’m looking for:
- Is there an official guide or example on how to configure provideKeycloak with SSR in Angular 19?
- Specifically, how should I handle the server-side environment when using Keycloak with Angular Universal?
- Any known issues or best practices for SSR with keycloak-angular in Angular 19?
I would appreciate any help or links to documentation.
Thank you in advance!
any comment on this request?
Hi @soungsid, I'll be working on an example SSR application using the library, along with documentation to support it. While I can't commit to a specific deadline, I’m aiming to have it ready by the end of February.
Hi, Are there any updates regarding SSR? Is the end of February deadline feasible?
@mauriciovigolo Any updates on this?
Hi, I saw the updates to keycloak-angular and tried it out with Angular 19 and SSR.
I had an issue with keycloak.init (window is not defined on the server) when using provideKeycloak(...).
It seems to work for me when the keycloak.init is only executed in the browser
const provideKeycloakInAppInitializer = (keycloak: Keycloak, options: ProvideKeycloakOptions): EnvironmentProviders | Provider[] => {
const { initOptions, features = [] } = options;
if (!initOptions) {
return [];
}
return provideAppInitializer(async () => {
const platform = inject(PLATFORM_ID);
// 👇 browser guard: only init keycloak in the browser
if (isPlatformBrowser(platform)) {
const injector = inject(EnvironmentInjector);
runInInjectionContext(injector, () => features.forEach((feature) => feature.configure()));
await keycloak.init(initOptions).catch((error) => console.error("Keycloak initialization failed", error));
} else {
console.log("Keycloak initialization skipped on server side");
}
});
};
What do you think about adding this check to provideKeycloakInAppInitializer?
Second, this is a change detection thing from Angular. Using the KEYCLOAK_EVENT_SIGNAL as described in the docs with effect to check authenticated, this will result in displaying Logout and Login button (when logged in) at the same time for RenderMode.Server, but only Logout for RenderMode.Client.
You can find my reproduction repo and fixes to both problems here: https://github.com/marcjulian/ng-19-ssr-keycloak
Let me know, if this helps solve the issue. Also let me know if I should create a PR to either add the isPlatformBrowser check or also to update docs/readme.
Thank you, Marc. Your explanations are wonderful, and your example works perfectly. Thanks to you, I'll be able to move forward with my Angular 19 / Keycloak project. Stephane
Currently trying to implement Keycloak Angular with Angular 20 and SSR and I currently face the same problem with both my application as well as the application you linked above: When reloading the app (or hot reloading when developing) after having logged in successfully, both apps seem to freeze up. They only return to working order once I remove the keycloak related cookies (which kind of defeats the purpose). Could this be related to a misconfigured Keycloak Setting or is this a known bug?
From what I noticed the KEYCLOAK_EVENT_SIGNAL never seems to fire
It's difficult to help you precisely based on your explanations. I'll share my code with you; maybe it will help.
interface KeycloakConfig { url: string; realm: string; clientId: string; }
export const keycloakConfig: KeycloakConfig = { url: environment.keycloak_protocol + '://' + environment.keycloak_ip + ':' + environment.keycloak_port, realm: environment.keycloak_realm, clientId: environment.keycloak_client_id, };
……
export class KeycloakServiceImpl {
private readonly injector = inject(Injector); private keycloak: any = undefined; private keycloakEventLast : KeycloakEvent | undefined = undefined; private keycloakSignalEvent : Signal<KeycloakEvent> | undefined;
……
public constructor() {
afterNextRender(async () => {
if (this.keycloak === undefined) {
// @ts-ignore
this.keycloak = new Keycloak(keycloakConfig);
this.keycloakSignalEvent = createKeycloakSignal(this.keycloak);
}
effect(
async () => {
if (this.keycloakSignalEvent === undefined) return;
let keycloakEvent: KeycloakEvent = this.keycloakSignalEvent();
if ( (keycloakEvent.type === this.keycloakEventLast?.type) && (keycloakEvent.args === this.keycloakEventLast?.args) ) return;
this.keycloakEventLast = keycloakEvent;
if (keycloakEvent.args !== undefined) --> TODO
}
},
{injector: this.injector}
);
});
}
Heya! Thanks for your answer. I sadly missed the response completely... I tried using the solution provided above by marcjulian (https://github.com/marcjulian/ng-19-ssr-keycloak) and implemented the services/fixes as mentioned. After playing around with it some more now I realised that the problem on my end seems to be with using locally signed SSL certificates for the angular application. On the initial load everything seems to be working fine, but whenever the application is reloaded (or changes in the codebase trigger a (partial) reload), the entire application freezes, causing no further communication with Keycloak (or anything else in the application to function for that matter). I highly doubt this issue stems from Keycloak or this library, thank you for your help regardless :)