giesekow / feathers-keycloak-connect

A light-weight library to connect keycloak and feathersjs at both server and client side.
7 stars 3 forks source link

Featherjs Keycloak Connector

A Lightweight library to secure feathersjs API with keycloak authentication with both server and client support.

Server Side

Install server library with npm:

Import and configure library with feathersjs application object

  import { AuthConfigure } from 'feathers-keycloak-connect-server';
  app.configure(AuthConfigure(keycloakServerOptions));

KeycloakServerOptions is an object with the following fields:

Once configured, the params object in feathers hooks and services will be patched with the user, client, and permissions object.

Hooks available

The library comes with hooks for performing security and access control. You can get the hooks object as follows import { hooks } from 'feathers-keycloak-connect-server'

hooks.protect

this hook checks if a user has logged in and if not will throw an access denied error!. This does not apply to internal server request where the params.provider field is undefined unless explicitly defined.

Example: To restrict the messages service to only logged in users.

import { hooks } from 'feathers-keycloak-connect-server';

app.service('messages').hooks({before: hooks.protect()});

hooks.restrictToOwner

use this to restrict an operation to the owner of the object. e.g. will be to only allow users to update their own profile. The hook takes two fields in the options object:

Example: To restrict patching of comments service by only the user who created it.

import { hooks } from 'feathers-keycloak-connect-server';

app.service('comments').hooks({before: {patch: hooks.restrictToOwner({ownerField: 'createdBy'})}});

hooks.hasRealmRole

this checks if the current user has a specific role or roles in the keycloak realm.

takes a string which represent the role we want to check or a list of roles. In the case of a list the user is granted access if he has atleast one of the roles in the list.

Example: restricting user creation to only users with admin role in keycloak.

import { hooks } from 'feathers-keycloak-connect-server';

app.service('users').hooks({before: {create: hooks.hasRealmRole('admin')}});

hooks.hasResourceRole

this is similar to the hasRealmRole hook. However this is checked against a specific resource and not the whole realm. This takes the ResourceAccessOptions object or a list of ResourceAccessOptions.

The ResourceAccessOptions is an object with two required fields

Where a list is provided, access is granted if the user has at least one of the requirements.

Example: Restrict the find method of the users services to only users with the account:view-profile resource-role.

import { hooks } from 'feathers-keycloak-connect-server';

app.service('users').hooks({before: {find: hooks.hasResourceRole({resource: 'account', role: 'view-profile'})}});

hooks.hasPermission

This hook checks if the current users passes the stated permission or atleast one of the group of permissions. For permissions to work you need to provide the secret field when configuring the library in the ``.

Configuring permissions in keycloak can be a little bit confusing check this link on stackoverflow here where people try to explain how to do this.

Example: Restrict the create method of the transactions service in feathersjs to only users who have a transactions:create permission in keycloak.

import { hooks } from 'feathers-keycloak-connect-server'`

app.service('transactions').hooks({before: {create: hooks.hasPermission({resource: 'transactions', scopes: 'create'})}})

The resource and scopes fields when any is ommitted will pick from the feathers service path and method respectively.

This means that the above example can be achieved through

app.service('transactions').hooks({before: {create: hooks.hasPermission()}})

hooks.getUser and hooks.getClient

these are utility hooks to retrieve the current user and client from the context object in the service hook.

Example: getting the current user in your custom hook.

import { hooks } from 'feathers-keycloak-connect-server';

function (options): {
  return async function(context) {
    const user = hooks.getUser(context);
    const client = hooks.getClient(context);
  }
}

Client Side

Install client library with npm:

Note: The client side code uses the keycloak-js behind the scence to login to keycloak and retrieve the jwt.

Import and configure library with feathersjs client object

  import { AuthConfigure } from 'feathers-keycloak-connect-client';
  ... configure other libraries ...
  app.configure(AuthConfigure(KeycloakClientConfig));

KeycloakClientConfig is an object with the following fields:

At the time of writing this documentation the required fields in the KeycloakConfig object are below. check official docs for any possible update or changes here:

At the time of writing this documentation the KeycloakInitOptions has no required fields (only optional fields) check official docs for any possible update or changes here relevant fields include:

Other options like adapter, checkLoginIframe, flow are also available. Check docs for more details.

Full Configuration example

import feathers from '@feathersjs/feathers';
import socketio from '@feathersjs/socketio-client';
import io from 'socket.io-client';
import { AuthConfigure } from 'feathers-keycloak-connect-client'

const socket = io('http://localhost:3030');
const app = feathers();

app.configure(socketio(socket));
app.configure(AuthConfigure(KeycloakClientConfig));

app.on('authSuccess', (payload: any) => {
  console.log('login-info', payload);
})

replace the socket.io-client with any other client you want and the steps should be the same. However library has been extensively tested with the socket.io client and guaranteed to work. report any problem you find with other clients.

Using library with vue-router.

Due to the nature and design of the vue-router library, you need to perform additional configuration in order to use this library with vue-router.

The library needs to perform feather processing after redirection from login and the redirection route has to be mounted to the library. this can be done as below.

const app = ... // feathersjs client already configured with the library
const router = ... // configured vue-router object

app.authentication.configureVueRouter(router);

Added properties or attributes

The following properties or attributes are available on the feathers client object after configuration:

authentication

The authentication library itself is accessible through this property.

keycloak

The keycloak object from keycloak-js library is also available here.

Added functions or methods

The following functions or methods are available on the feathers client object after configuration:

authenticated

A function which returns true if user has logged in or false otherwise.

authenticate | login

A function which can be used to trigger the login action. That's redirect user to keycloak for authentication. Parameters are: