Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Shoot'nShare backend

What is it?

A simple example to demo OAuth2 authorization code grant with Keycloak.

How do I run it?

Local Docker

TODO Update

#Build local 
docker build --tag shoot-rest-local . -f docker/rest-local/Dockerfile


Create a new project

oc new-project shoot-and-share

PS: You can use whatever project name you like

Import template

oc create -f https://raw.githubusercontent.com/aerogear/aerogear-backend-cookbook/master/Shoot/deploy/openshift/template.yaml

Add to project

  1. Go to project overview
  2. Click on the Add to project button
  3. Select the Uncategorized
  4. Select shoot-demo-template
  5. Fill in the Namespace with "shoot-and-share"
  6. Clik in create button

Client Apps

Upload an image using one of our Shoot and Share example app

The app flow

  1. Go to http://localhost:8080/shoot/photos/ or http://rest. (if you are using openshift)
  2. Login using user / password
  3. See the picutres uploaded

Shoot'nShare web-app

How does it work?

Upload from your phone with OAuth2 client

In the Keycloak realm configuration/shoot-realm.json, create an application for your rest endpoint (your services) Here we define bearerOnly as this end-point will not be used for login, it does not offer any redirect urls, it is just a plain OAuth2 service.

"applications" : [ {
    "name" : "shoot-services",
    "enabled" : true,
    "bearerOnly" : true,
    "publicClient" : true

You should also define a OAuht2 client, the name shoot-third-party should match your client_id in your client app and the redirectUris is the redirect_uri.

"oauthClients" : [ {
    "name" : "shoot-third-party",
    "redirectUris" : [ "org.aerogear.Shoot://oauth2Callback" ],
    "webOrigins" : [ ],
    "enabled" : true,
    "publicClient" : true
} ]

Define your services to list, upload, get images. (Check src/main/java/org/jboss/aerogear/shoot/PhotoService.java)

To secure your endpoints, user wildfly Keycloak adapter. This simple demo uses a "per war approach". Refer to Keycloak adapters chapter for more details Go in src/main/webapp/WEB-INF/web.xml




NOTE: For simplicity our demo does not use https BUT all OAuth2 protected REST points should be using SSL. If you are using WildFly or EAP follow this link to enable HTTPS or consult your application server's documentation page.

and use src/main/webapp/WEB-INF/keycloak.json, you link your java endpoint with Keycloak realm application. Here the application is names shoot-services

    "realm": "shoot-realm",
    "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCUgrGF7rNIYRSWCZlT+JXGtjZtnn8/ZObzW12YSoRBUJ0mm6wzO6p8+aQYMXvtvB88zeWBD9+uZh8gWj+iOqByWCfX0Wez+mVK8ofhAsGniv631u+wmDESLrLvROX12r1fzmmVJYWOzEGW4v2Xmahl/6gHnzV0mHZfmJXEOniHqwIDAQAB",
    "auth-server-url": "/auth",
    "bearer-only": true,
    "ssl-required": "external",
    "resource": "shoot-services"

View all users images in web-app

The web-app is using angular, the webapp\photos\js\app.js loads the configuration file webapp\config\keycloak.json.

    "realm": "shoot-realm",
    "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCUgrGF7rNIYRSWCZlT+JXGtjZtnn8/ZObzW12YSoRBUJ0mm6wzO6p8+aQYMXvtvB88zeWBD9+uZh8gWj+iOqByWCfX0Wez+mVK8ofhAsGniv631u+wmDESLrLvROX12r1fzmmVJYWOzEGW4v2Xmahl/6gHnzV0mHZfmJXEOniHqwIDAQAB",
    "auth-server-url": "/auth",
    "ssl-required": "external",
    "resource": "shoot-web",
    "public-client": true

where shoot-web matches an application define in realm configuration/shoot-realm.json.

webapp\photos\js\app.js configures an auth intercepter. Each http calls will be intercepted and added relevant authorization headers.

module.factory('authInterceptor', function($q, Auth) {
    return {
        request: function (config) {
            var deferred = $q.defer();
            if (Auth.authz.token) {
                Auth.authz.updateToken(5).success(function() {
                    config.headers = config.headers || {};
                    config.headers.Authorization = 'Bearer ' + Auth.authz.token;

                }).error(function() {
                        deferred.reject('Failed to refresh token');
            return deferred.promise;


In your realm you have one web app shoot-web, secure services endpoints shoot-services and one OAuth2 client shoot-third-party.