Skip to content

JSON Web Token based Authentication powered by Keycloak

License

Notifications You must be signed in to change notification settings

felixheck/hapi-auth-keycloak

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 Cannot retrieve latest commit at this time.

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

hapi-auth-keycloak

JSON Web Token based Authentication powered by Keycloak

Travis node npm standard npm Coverage Status

  1. Introduction
  2. Installation
  3. Usage
  4. API
  5. Example
  6. Developing and Testing
  7. Contribution

Introduction

hapi-auth-keycloak is a plugin for hapi.js which enables to protect your endpoints in a smart but professional manner using Keycloak as authentication service. It is inspired by the related express.js middleware. The plugin validates the passed Bearer token online with help of the Keycloak server and optionally caches successfully validated tokens and the related user data using catbox. The caching enables a fast processing although the user data don't get changed until the token expires. It plays well with the hapi.js-integrated authentication feature. Besides the authentication strategy it is possible to validate tokens by yourself, e.g. to authenticate incoming websocket or queue messages.

This plugin is implemented in ECMAScript 6 without any transpilers like babel.
Additionally standard and ava are used to grant a high quality implementation.

Installation

For installation use the Node Package Manager:

$ npm install --save hapi-auth-keycloak

or clone the repository:

$ git clone https://github.com/felixheck/hapi-auth-keycloak

Alternatively use the Yarn Package Manager:

$ yarn add hapi-auth-keycloak

Usage

Import

First you have to import the module:

const authKeycloak = require('hapi-auth-keycloak');

Create hapi server

Afterwards create your hapi server and the corresponding connection if not already done:

const server = new Hapi.Server();

server.connection({
  port: 8888,
  host: 'localhost',
});

Registration

Finally register the plugin, set the correct options and the authentication strategy:

server.register({
  register: authKeycloak,
  options: {
    client: {
      realmUrl: 'https://localhost:8080/auth/realms/testme',
      clientId: 'foobar',
      secret: '1234-bar-4321-foo'
    },
    cache: {}
  }
}, function(err) {
  if (err) {
    throw err;
  }

  server.auth.strategy('keycloak-jwt', 'keycloak-jwt');
});

Route Configuration & Scope

Define your routes and add keycloak-jwt when necessary. It is possible to define the necessary scope like documented by the express.js middleware:

  • To secure a resource with an application role for the current app, use the role name (e.g. editor).
  • To secure a resource with an application role for a different app, prefix the role name (e.g. other-app:creator)
  • To secure a resource with a realm role, prefix the role name with realm: (e.g. realm:admin).
server.route([
  {
    method: 'GET',
    path: '/',
    config: {
      description: 'protected endpoint',
      auth: {
        strategies: ['keycloak-jwt'],
        access: {
          scope: ['realm:admin', 'editor', 'other-app:creator']
        }
      },
      handler (req, reply) {
        reply('hello world')
      }
    }
  },
])

API

Plugin Options

  • client {Object}: The configuration of keycloak-auth-utils its GrantManager. The suggested minimum configuration contains realmUrl, clientId and secret.
    Required.

  • cache {Object|false}: The configuration of the hapi.js cache powered by catbox.
    If false the cache is disabled. Use an empty object to use the built-in default cache.
    Optional. Default: false.

server.kjwt.validate(field {string}, done {Function})

Uses internally GrantManager.prototype.validateAccessToken().

  • field {string}: The Bearer field, including the scheme (bearer) itself.
    Example: bearer 12345.abcde.67890.
    Required.

  • done {Function}: The callback handler is passed err {Error}, result {Object|false} (error-first approach).
    If an error occurs, err is not null. If the token is invalid, the result is false. Otherwise it is an object containing all relevant credentials.
    Required.

Example

const Hapi = require('hapi');
const authKeycloak = require('hapi-auth-keycloak');

const server = new Hapi.Server()
server.connection({ port: 3000, host: 'localhost' })

server.route([
  {
    method: 'GET',
    path: '/',
    config: {
      description: 'protected endpoint',
      auth: {
        strategies: ['keycloak-jwt'],
        access: {
          scope: ['realm:admin', 'editor', 'other-app:creator']
        }
      },
      handler (req, reply) {
        reply('hello world')
      }
    }
  },
])

process.on('SIGINT', () => {
  server.stop().then((err) => {
    process.exit((err) ? 1 : 0)
  })
})

server.register({
  register: authKeycloak,
  options: {
    client: {
      realmUrl: 'https://localhost:8080/auth/realms/testme',
      clientId: 'foobar',
      secret: '1234-bar-4321-foo'
    },
    cache: {}
  }
}).then(() => {
  server.auth.strategy('keycloak-jwt', 'keycloak-jwt');
  server.start()
})
.catch(console.error)

Developing and Testing

First you have to install all dependencies:

$ npm install

To execute all unit tests once, use:

$ npm test

or to run tests based on file watcher, use:

$ npm start

To get information about the test coverage, use:

$ npm run coverage

Contribution

Fork this repository and push in your ideas.

Do not forget to add corresponding tests to keep up 100% test coverage.
For further information read the contributing guideline.