OAuth made easier with Feathers v4/v5, OpenID Connect and Keycloak

Luc Claustres
The Feathers Flightpath
6 min readSep 20, 2022

--

In this article we detail a running setup to authenticate users in your Feathers app based on either their account from public identity providers like Google or enterprises-grade solutions like Keycloak able to integrate with their directories behind a corporate firewall.

Preambule

In previous articles we already detailed how you can setup OAuth in FeathersJs v3 with public identity providers or enterprise-grade Single Sign-On (SSO) solutions. Please refer to these articles if you are not used to OAuth flow and concepts as we assume here you are already familiar with Feathers and OAuth.

Identity as a Service (IDaaS) is cloud-based authentication operated by a third-party provider. This article will demonstrate how Feathers v4/v5 and its new authentication system make it easier to implement. Notably by relying on OpenID Connect, a layer on top of OAuth 2.0 enabling to verify the identity of the user as well as to obtain basic profile information in an interoperable manner, which is now supported by most identity providers.

1. Define your OAuth strategy

Feathers provides you with a default OAuth strategy that you can customize for your own needs. This strategy creates (respectively updates) an entity (i.e. user) object in your local user service the first time (respectively the following times) you log in using an identity provider. If the identity provider is namedxxx, then the created entity will store the remote user ID as thexxxIdproperty. This ID is used to match the user whenever he logs in again with this provider.

Here we will create our own strategy by extending the default one in order to:

  • store in addition the retrieved profile information from the identity provider in the entity object (under the xxxproperty),
  • allow to login with either the local or OAuth strategy using the same account by matching the retrieved entity via email address in addition to provider user ID.

There are various methods you can override to customize the strategy, the key ones being:

  • getEntityData(), which returns the entity object to be stored in your user service,
  • getEntityQuery(), which returns the query used to match a given identity provider user with a local user.

The new strategy looks like this:

Using OpenID Connect the returned access token from the provider will contains addition claims (i.e. fields or properties) that are identity information about the user, which will be available in the profileobject (under the xxxproperty of the entity).

2. Configure your backend

What we’d like to achieve is to be able to register new identity providers easily, i.e. by configuration, without requiring to update the application. After registering your application to an identity provider, you will receive a client ID and a client secret to be used as configuration items. To use OpenID Connect you also have to specify the scope parameter, i.e. the reason for which you are asking for the token. I specified openid, profile, and email, which are scopes that cause the authorization server to issue an ID token with a particular layout, e.g. enriched with profile and email information of the user. Here is an example of a configuration file to use OpenID Connect for a wide range of identity providers (GitHub, Google, AWS Cognito, Keycloak):

In order to setup Feathers based on this configuration file, we simply iterates over the different providers found in the OAuth section and instantiate our strategy for each one, in addition to the standard authentication setup:

3. Configure your frontend

Based on your OAuth configuration, Feathers will create an endpoint for each provider based on the configuration keys. For instance, you will be able to login with Keycloak using the your.domain.com/oauth/keycloak URL. So making your frontend use OAuth is just a matter of calling the right endpoint when the user wants to authenticate using a dedicated provider in your app the first time or when his session has expired:

<a href="/oauth/keycloak">Login With Keycloak</a>

When selecting the link, you should see the login screen of your provider, e.g. Keycloak:

Then you should be redirected to the home page of your app if authentication is successful.

What remains to do is to ensure that if the user already has an active session he does not need to login manually and will be automatically redirected to the home page of your app. For this, simply install the @feathersjs/client module (npm install @feathersjs/client), then use the restoreSession()function in your index page to check for an existing session and retrieve the corresponding user profile once your client has been initialized:

If the function fails then you should redirect to the login page to start a new session.

4. Configure your own identity provider

From the developer perspective the key advantages of OAuth is to be able to quickly add a robust authentication mechanism into a web app and delegate most implementation and security concerns to the provider (e.g. password reset, email verification, token revocation, etc.). Although it is convenient, a lot of a security professionals will caution you against connecting your apps to “social account providers” like Google if it does not provide you with a real benefit. Moreover, enterprises often need solutions able to integrate with their own directories behind a corporate firewall and not relying on public providers. As a consequence, it can be required to implement your own identity provider. In this article we focus on a working setup for Keycloak, which is a fully-featured Open Source Identity and Access Management solution.

After creating your administrator account, create realm(s) to manage the set of users of your application(s). Indeed, realms are isolated from one another and can only manage and authenticate the users that they control. Creating a single realm shared by all yours apps will result in a Single Sign-On (SSO) approach, while creating different realms will result in an isolated authentication for each application. A lot of login options are available: forgot password link, registration link, remember me, verify email, etc. You can also let Keycloak manage third-party identity providers for you. This way you can add or remove an identity provider without requiring updating your application. Indeed, no code is required in your application, all of this is just a matter of toggling options in the Keycloak administration server UI. Here is a typical login screen for your app with different login options enabled and the Google identity provider added to the local authentication:

The last thing to do to connect your application(s) to the realm(s) is to create a client for each application using the OpenID Connect protocol. Simply copy-paste the client ID/secret in the application configuration example given above and that’s it !

When delegating users management you often need to retrieve custom metadata associated to users by the provider. Typically, we will now detail how to get their roles in the realm and use it in your application. Adding a Mapper to your client allows to tailor what claims (i.e. fields) will be included in the authentication token. First, create a built-in mapper with the following properties:

  • Name: roles
  • Mapper Type: User Realm Role
  • Token Claim Name: roles
  • Claim JSON Type: String

Second, create the different roles you need in your realm and assign it to your users. Last, access the role from the retrieved profile of the users in your app to implement specific behaviors, e.g. in a hook:

context => {
const user = context.params.user
const roles = user.keycloak.roles
if (roles.includes('admin')) {
// do something requiring the admin role
}
}

Conclusion

We hope you now know how to make your FeathersJS app OAuth-friendly.

If you liked this article feel free to have a look at our Open Source solutions and enjoy our other articles on Feathers, the Kalisio team !

This article would have not been possible without the support of David Luecke, the creator of FeathersJS.

--

--

Digital Craftsman, Co-Founder of Kalisio, Ph.D. in Computer Science, Guitarist, Climber, Runner, Reader, Lover, Father