Fork me on GitHub

Programming, Internet & more

Authentication with Spring Boot, AngularJS and Keycloak

Update

There is a new version of this tutorial available for Angular 2 and Keycloak.

Intro

In this tutorial, I want to show you how to combine Keycloak with AngularJS and Spring Boot.

The result will be a small application where you will get a frontend written in AngularJS and the big topics regarding authentication like user-registration, password reset, login page etc. are already solved.

The backend is implemented with Spring Boot and will provide a REST API with business services exposed. Authentication in the backend is also solved by using Keycloak which means that all REST endpoints will be secured and that you will get all the user information in the backend as well as in the frontend.

Requirements

We will use the following tools and frameworks to build the application:

Maven (Version 3.3.9)
Spring Boot (Version 1.3.3.RELEASE)
Keycloak (Version 1.9.1.Final)
AngularJS (Version 1.5.0)

Create a realm in Keycloak

Start up Keycloak by using one of the Standalone executeables in the /bin directory of Keycloak which will start Keycloak immediately by using the bundled WildFly application server.

After the startup, open up a browser and navigate to http://localhost:8080.

If this is the first time you start Keycloak it is required to create an admin user.

After you have created the admin user, use this user to login into the Administration Console. By default Keycloak uses the Master realm to manage its own users. You should never use this realm to authenticate your own application. Instead create your own realm for the authentication of your application.

Create a new realm by hovering over the Master realm and click on the “Add realm” button. Enter a name, we will use Demo-Realm, and click on “Create”. After that you will be navigated to the configuration page of the realm.

Open the “Login” tab and enable the features “User registration” and “Forgot password”. By enabling, these features will be added to the login page automatically and will cover the common use-cases that appear in nearly every web application.

Create roles in Keycloak

Now, lets add some roles that can be assigned to users later on to handle authorization. We need two roles that will come into play later on. One is the admin role and the other one is the manager role.

Click on the “Roles” link in the navigation and after that, click on the button “Add Role” at the right side of the screen. This will navigate you to the “Add Role” screen. Enter admin as role name and click on “Save”. Create another role named manager.

Create clients in Keycloak

After we have created our roles we can create the clients for our application. We will need two clients. One for the frontend application and one for the REST backend.

Let’s start by creating the frontend client. Click on the “Clients” link in the navigation and then use the “Create” button to create a new client.

Use tutorial-frontend as client id and click on “Save”.

You will be navigated to the client settings. Use the access type public and the following URLs and save the client:

  • Valid Redirect URIs: http://localhost:8000/*
  • Base URL: http://localhost:8000/index.html
  • Web Origins: http://localhost:8000

Now the frontend client is completely configured and can be used.

Lets create another client for the backend and name it tutorial-backend. This time configure the access type as bearer-only because the REST backend should only be called when a user has already logged in.

Now the basic configuration in Keycloak is done and we can start building the applications.

Frontend application with AngularJS

We want to build a small Angular application that is secured by a login page and where access is restricted to registered users only. Therefore every request which goes to the Angular application should be checked if it comes from a registered user or not. If a request does not come from a registered user, the request will be redirected to the login page where a user can register.

To interact with Keycloak from our AngularJS application, Keycloak is providing a JavaScript-Adapter directly on the Keycloak server. This adapter will be used to check if a request is authenticated and can be integrated in our application by including the JavaScript file into our html page:

<script src="//localhost:8080/auth/js/keycloak.js"></script>

Futhermore we have to configure the KeyCloak adapter to ensure it knows who our application is and where to find the Keycloak server. We can provide this information as a json file which can be downloaded directly from the Keycloak server.

To get the json file, open the Keycloak administration console and navigate to the frontend client page. Then open the “Installation” tab and choose “Keycloak OIDC JSON” as format. Then download the JSON file and store it in the angular application as /keycloak/keycloak.json.

One important thing to know is because we are only allowing registered users to have access to the application we have to manually bootstrap AngularJS and we cannot rely on the automatic bootstrapping with the ng-app directive.

The following code demonstrates how to authenticate a request and bootstrap angular only if the request comes from a registered user:

// on every request, authenticate user first
angular.element(document).ready(() => {
    window._keycloak = Keycloak('keycloak/keycloak.json');

    window._keycloak.init({
        onLoad: 'login-required'
    })
    .success((authenticated) => {
        if(authenticated) {
            window._keycloak.loadUserProfile().success(function(profile){
                angular.bootstrap(document, ['keycloak-tutorial']); // manually bootstrap Angular
            });
        }
        else {
            window.location.reload();
        }
    })
    .error(function () {
        window.location.reload();
    });
});

If an unregistered user opens the application he will be automatically redirected to the Keycloak login page. In the application we can access user information like login name by getting the user profile with loadUserProfile().

That is basically all what is needed to secure our Angular application. To ensure the user information is transmitted to the backend we also have to add the users access token to the request header while calling a backend REST service. This can be done like this application wide:

// use bearer token when calling backend
app.config(['$httpProvider', function($httpProvider) {
    var token = window._keycloak.token;    
    $httpProvider.defaults.headers.common['Authorization'] = 'BEARER ' + token;
}]);

Backend application with Spring Boot

The backend application should be secured against unauthorized access. Therefore, like in the frontend, only requests coming from registered users should be accepted.

First, it is important to add the maven Keycloak dependencies for Tomcat and Spring Boot:

<dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-tomcat8-adapter</artifactId>
            <version>${keycloak.version}</version>
        </dependency>
        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-spring-boot-adapter</artifactId>
            <version>${keycloak.version}</version>
        </dependency>

Then we have to configure keycloak just like we did in the frontend application. This time the configuration is done the Spring Boot way in the application.properties file:

keycloak.realm = Demo-Realm
keycloak.realmKey = MI...
keycloak.auth-server-url = http://localhost:8080/auth
keycloak.ssl-required = external
keycloak.resource = tutorial-backend
keycloak.bearer-only = true
keycloak.credentials.secret = e12cdacf-0d79-4945-a57a-573a833c1acc

The values can be retrieved from the “Installation” tab in the administration console of Keycloak for the backend client. One important thing here is to not forget the secret. The secret can be retrieved from the “Credentials” tab of the backend client.

To secure the REST API endpoints a few other entries in the application.properties file are important:

keycloak.securityConstraints[0].securityCollections[0].name = spring secured api
keycloak.securityConstraints[0].securityCollections[0].authRoles[0] = admin
keycloak.securityConstraints[0].securityCollections[0].authRoles[1] = manager
keycloak.securityConstraints[0].securityCollections[0].patterns[0] = /api/*

The patterns property defines the pattern of the API endpoints with * acting as wildcard. That means every endpoint under api like /api/contracts or /api/users is protected by Keycloak. Every other endpoint that is not explicitly listed is NOT secured by Keycloak and is publicly available.

The authRoles property defines which Keycloak roles are allowed to access the defined endpoints.

If everything is configured correctly the Keycloak adapter for Spring Boot should intercept incoming request automatically and reject unauthorized requests.

To access detailed user information in the backend we can use the KeycloakPrincipal class from the Keycloak-SpringBoot adapter. The KeycloakPrincipal will automatically be injected by Spring if used in a REST controller class as method parameter. Detailed user information can then be retrieved by using the AccessToken like this example in a REST controller:

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public void getUserInformation(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal) {
        AccessToken token = principal.getKeycloakSecurityContext().getToken();
       
        String id = token.getId();
        String firstName = token.getGivenName();
        String lastName = token.getFamilyName();

        // ...
    }

In the full example you will see that I have build a MethodArgument Resolver to avoid having to deal with the Principal in the REST controllers but that is absolutely not necessary and just for convenience.

Demo

The simplest way to start up a demo is to clone the application source with:

git clone https://github.com/cternes/slackspace-angular-spring-keycloak

Then you can either configure the frontend and backend application with the correct settings from Keycloak as described above OR use the existing KeyCloak configuration in keycloak/demo-realm.json to import the realm in Keycloak and avoid having to manually configure the applications.

After that use maven to start both applications with the following command:

mvn spring-boot:run

Then navigate to http://localhost:8000 and you should find yourself landing on the Keycloak login page. Register yourself as a new user. After registering you will be redirected back to the Angular application and should see some details about your user.

Please note that currently your user is not associated to any role defined earlier. That means accessing the backend is impossible because we have only allowed managers and admins to access the backend. To give your user access to the backend we have to map your user to a role.

To do this, open the Keycloak admin console and navigate to “Users”. Then click on the button “View all users” and click on your username. After that navigate to the “Role Mappings” tab and assign the role “manager” to your user.

Now open up the Angular app again and you should see a “Call backend service” button that only managers can see. Click on it and some contracts from the backend should be returned together with your user information which comes also from the backend.

This proves that the frontend and the backend is correctly secured by Keycloak.

Source-Code

As always, you can find a full working example at GitHub.

Category: spring
-->

18 Comments

  1. Manuel Palacio
    Posted June 3, 2016 at 13:57 | Permalink

    Excellent tutorial. Thank you! Do you happen to know if it’s possible to use KeyCloak’s client libraries to integrate with other SSO solutions that support SAML?

    • Christian
      Posted June 3, 2016 at 15:00 | Permalink

      I don’t know for sure but as the JS adapter is written for keycloak, I doubt that it will work with another provider.

      • Manuel Palacio
        Posted June 6, 2016 at 12:21 | Permalink

        You are right, it’s not going to work. My plan is to develop my application to integrate with KeyCloak like in your tutorial and then use KeyCloak as the identity broker that integrates with other IDPs. That should work fine. Thanks.

  2. Preethi
    Posted July 1, 2016 at 16:45 | Permalink

    Excellent Tutorial.I see some issue in accessing the application via IE11.

  3. Daniel Abella
    Posted August 9, 2016 at 14:22 | Permalink

    Great tutorial! The best tutorial about this technology.

  4. Posted October 24, 2016 at 21:26 | Permalink

    Awesome! Trying it out now…

    • Posted October 24, 2016 at 21:48 | Permalink

      Working perfectly! I was having some issue to get this working and internet lacks of resource on this topic. I’m glad I found this article and thank you for sharing.

  5. Layi Egbeyemi
    Posted November 30, 2016 at 12:04 | Permalink

    Love this. Nice and concise!

  6. Umasankar
    Posted December 7, 2016 at 22:08 | Permalink

    Excellent…Executed without a single issue.. Thanks!

  7. Umasankar
    Posted December 8, 2016 at 21:56 | Permalink

    Excellent Tutorial.. Working without any issue

  8. DM
    Posted January 11, 2017 at 20:35 | Permalink

    Thanks for a great tutorial!

    Do you know how to configure the Spring Boot app to support multiple realms/clients in Keycloak? Currently, we are only setting up one realm/client in application.properties. I know that Keycloak supports multi-tenancy but I could not find any articles on how to achieve this with Spring Boot.

  9. Posted January 17, 2017 at 16:07 | Permalink

    Great step you have define it is really helpful for all developer making

  10. Ricardo
    Posted January 19, 2017 at 14:50 | Permalink

    I tried to build a realm (Keycloak 2.3) from scratch, I always get the bearer message (clicking in the rest button). When I create through your file, all works fine. Already compared side by side both realms, I don’t know what’s wrong.

    But it’s ok. Now my next step is learn Angular 2. I know nothing about it, not even the first one (yeah, I know they are completely different).
    So, lemme ask… do you intend to update your code using Angular 2? I’m having a hard time trying to make it work.

  11. Posted March 7, 2017 at 12:49 | Permalink

    Hi,

    I have followed your tutorial and created a similar HTML application (which uses keycloak.json) with social authentication and a sample REST resource which I have implemented similar to tutorial-backend.

    However, once I am successfully authenticated using google and also have the right roles assigned (as per your tutorial). I see the following error in the “resource” server log:

    2017-03-07 15:09:14.953 DEBUG 6932 — [nio-9000-exec-1] o.k.adapters.KeycloakDeploymentBuilder : Use authServerUrl: http://xyz.us-west-2.elb.amazonaws.com:8080/auth, tokenUrl: http://xyz.elb.amazonaws.com:8080/auth/realms/springboot/protocol/openid-connect/token, relativeUrls: NEVER
    2017-03-07 15:09:16.535 DEBUG 6932 — [nio-9000-exec-1] o.k.a.rotation.JWKPublicKeyLocator : Realm public keys successfully retrieved for client greet. New kids: [ZshfMDRRRXO1z7b6M5gJnIeFz2MxqVSZwgLvH3CVE_U]
    2017-03-07 15:09:16.546 WARN 6932 — [nio-9000-exec-1] o.k.adapters.RequestAuthenticator : SSL is required to authenticate

    Can you give me some pointers?

    Regards,
    Vidyashree

  12. Marc
    Posted March 16, 2017 at 15:41 | Permalink

    Very good tutorial. We used it as first step to get keycloak working at all and to get a practical understanding of whats going on.

    Just some notes:
    We used a more recent keycloak version 2.5.4.Final which worked fine. At least in this versions it seems that the public key is not needed in configs, since the adapters pulling them from keycloak when they need them.

    And this here http://slackspace.de/articles/cors-with-keycloak-and-spring-boot is very important if you go for further services. Its a small detail, but it really gave us some head scratching 😉

    Thanks for sharing!

  13. jijesh vu
    Posted April 17, 2017 at 12:51 | Permalink

    How to map client role in application.properties.
    When I add client role giving forbidden error.

  14. peter
    Posted May 15, 2017 at 17:33 | Permalink

    hi,after do this all ,I can visit the session page,But when I CALL the restful services, the errors in the console line like
    this :
    [http-nio-8000-exec-10] ERROR o.k.a.BearerTokenRequestAuthenticator – Failed to verify token
    org.keycloak.common.VerificationException: Invalid token signature.
    at org.keycloak.RSATokenVerifier.toAccessToken(RSATokenVerifier.java:73)
    at org.keycloak.RSATokenVerifier.verifyToken(RSATokenVerifier.java:39)
    at org.keycloak.RSATokenVerifier.verifyToken(RSATokenVerifier.java:35)
    at org.keycloak.adapters.BearerTokenRequestAuthenticator.authenticateToken(BearerTokenRequestAuthenticator.java:87)
    at org.keycloak.adapters.BearerTokenRequestAuthenticator.authenticate(BearerTokenRequestAuthenticator.java:82)
    at org.keycloak.adapters.RequestAuthenticator.authenticate(RequestAuthenticator.java:65)
    at org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve.authenticateInternal(AbstractKeycloakAuthenticatorValve.java:206)
    at org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve.authenticate(KeycloakAuthenticatorValve.java:48)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:577)
    at org.keycloak.adapters.tomcat.AbstractKeycloakAuthenticatorValve.invoke(AbstractKeycloakAuthenticatorValve.java:187)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
    23:23:54.556 [http-nio-8000-exec-10] DEBUG o.k.adapters.RequestAuthenticator – Bearer FAILED

Post a Comment

Your email is kept private. Required fields are marked *

*
*