Reputation: 103
Very new to both Aurelia and keycloak and trying to get the two to work together. Using the Aurelia production seed without typescript
I am trying to follow this example that uses Angular2 keycloak-angular2
there is also an angular1 example in that repo
Steps taken so far (I have updated the code snippet with additional progress)
1) Added the bower-jspm endpoint and installed keycloak.js
2) Added a keycloak-service.js (Updated)
```
import {keycloak} from 'keycloak';
import {LogManager} from 'aurelia-framework';
let logger = LogManager.getLogger('KeycloakService');
export class KeycloakService {
static auth = {};
static init() {
let keycloakAuth = new Keycloak({
"realm": "my-realm",
"url": "http://localhost:8080/auth",
"ssl-required": "external",
"clientId": "CID"
});
KeycloakService.auth.loggedIn = false;
return new Promise(function(resolve, reject) {
keycloakAuth.init({ onLoad: 'login-required' })
.success(() => {
logger.debug("Init Success");
KeycloakService.auth.loggedIn = true;
KeycloakService.auth.authz = keycloakAuth;
KeycloakService.auth.logoutUrl = keycloakAuth.authServerUrl + "/realms/my-realm/tokens/logout?redirect_uri=/";
resolve(null);
})
.error(() => {
logger.debug("Init Failed");
reject(null)
});
});
}
logout(){
logger.debug("Logging out");
KeycloakService.auth.loggedIn = false;
KeycloakService.auth.authz = null;
window.location.href = KeycloakService.auth.logoutUrl;
}
getToken() {
return new Promise(function(resolve, reject) {
if (KeycloakService.auth.authz.token) {
logger.debug("Refreshing token");
KeycloakService.auth.authz.updateToken(5)
.success(function() {
logger.debug("Token refreshed");
resolve(KeycloakService.auth.authz.token);
})
.error(function() {
logger.debug("Failed to refresh token");
reject('Failed to refresh token');
});
}
});
}
}
```
3) In the main.js (Updated),
```
import {KeycloakService} from 'keycloak-service';
export function configure(aurelia) {
aurelia.use
.standardConfiguration()
.developmentLogging();
KeycloakService.init()
.then(() => aurelia.start().then(() => aurelia.setRoot()));
}
```
When i go to localhost:9000 , it redirects me to the login page, and allows me to login and takes me to the welcome page. Everytime i refresh the localhost:9000 page, it does not remember my previous login (even though my keycloak session is active) and forces me to login again. I am guessing this is due to onload login required. Though shouldnt it remember that i am already logged in?
After logging in, the console shows an error "keycloak.js:828 Uncaught TypeError: Cannot read property 'postMessage' of null" on checkLoginIframe.
I am not sure how to implement the route/http interceptor
I tried creating a simple class to hit a health endpoint at the server
```
import {inject} from 'aurelia-framework';
import {HttpClient} from 'aurelia-fetch-client';
import {KeycloakService} from 'keycloak-service';
import {LogManager} from 'aurelia-framework';
import 'fetch';
let logger = LogManager.getLogger('health');
@inject(HttpClient, KeycloakService)
export class Health {
constructor(http, keycloakService) {
http.configure(config => {
config
.useStandardConfiguration()
.withBaseUrl('http://localhost:8081/api/health/')
.withDefaults({
headers: {
'X-Requested-With': 'Fetch'
}
});
});
this.http = http;
this.keycloakService = keycloakService;
}
activate() {
return this.keycloakService.getToken().then(
token => {
// Somehow add this token to the header ...
this.http.fetch('summary').then(response => response.json())
}
);
}
}
```
However this fails with the same checkLoginIFrame issue again. Also unsure how i would inject the bearer token header at this point. Is there a better way to intercept this globally (or semi globally for certain routes) or should i create a superclass and extend all the services with it that need to send a token to the server.
I am trying to get to a point where the welcome screen is not secured, and possibly a search screen that is not secured, (so i wouldnt do onLoad: 'login-required'. I want to have a explicit link for login/signup on main page. And the rest of the navigation requires the user to be logged in
Has any one successfully achieved this and can share some code? As i said, primarily a server side dev with limited angular 1 experience and evaluating keycloak as well so pretty much uncharted waters with all this stuff
Oh and i couldnt just copy the keycloak.json from the keycloak console installation tab as is, had to change "resource" to "clientId" and "auth-server-url" to "url", is that normal behaviour?
---- UPDATE ----
so after debugging, the document.body.appendChild(iframe);
does set the contentWindow on the iframe, but when the checkLoginIframe
gets called after the interval expires, the contentWindow for some reason is changed to null. I guess it has something to do with when I do the init vs when aurelia is done doing its thing, i tried calling init at different points, but then the router gets in the way of things. Since i do not need to do load on init, i just do the init on configure in main.js and at least for now this issue goes away.
Using the js-console demo from keycloak as an example, i am trying to implement explicit login. The login button takes me to the keycloak login page, however on logging in, the issue i am running into now is that the aurelia router complains that `Error: Route not found: http://localhost:9000/?redirect_fragment=%2Fkcr#state=...&code=...' where kcr is the html/js route module i am using to put some buttons on the screen to test the functionality
thanks
Upvotes: 1
Views: 4605
Reputation: 5341
Initializing Keycloak with
keycloakAuth.init({onLoad: 'login-required', checkLoginIframe: false})
solved the problem for me.
The reason seems to be that the checkLoginIframe element is only correctly created and added to the dom if you configure onLoad: 'check-sso'
. But that's only a guess informed by looking at and debugging through keycloak.js
. If my guess is correct, keycloak.js
should get some better configuration error handling.
Upvotes: 1
Reputation: 11
See Aurelia-Keycloak.
Alpha version. An authentication plugin based on KeyCloak for Aurelia applications.
Install Aurelia-Keycloak:
jspm install aurelia-keycloak
Add keycloak configuration and initialization settings:
Follow Keycloak directions for creating a keycloak.json configuration file. Put this file in the same directory as your application's index.html file. Refer to the keycloak javascript adapter documentation for its initialization options and API.
.plugin('aurelia-keycloak', {initOptions:{ onLoad: 'login-required' }})
.plugin('aurelia-keycloak')
Then, construct a login button within your code to call the keycloak login function.`.plugin('aurelia-keycloak',{install:{PASTE GENERATED KEYCLOAK.JSON HERE}},initOptions:{ onLoad: 'login-required' }}
See the GITHUB for details.
Upvotes: 0