Keycloak Authentication and Authorization in GraphQL

Dara Hayes
5 min readNov 15, 2019

A lot of the challenges teams face on their GraphQL journey are things that have been fairly well understood in the RESTful world for a long time. One of those things is Authentication and Authorization.

There’s a lot of content covering authentication and authorization in GraphQL APIs. To summarise, there are two main ways to do it.

1. Authentication at the HTTP Level.

In this scenario you enforce authentication on your entire GraphQL endpoint. There are plenty of libraries and middlewares that do this. Depending on your needs, this approach is perfectly fine in a GraphQL API, but there is a lot more that can be done.

2. Authentication at the GraphQL Level.

With the GraphQL context and schema directives, you can access the incoming request, perform your auth logic, and make the user details available in the GraphQL resolvers. While the first approach is pretty standard on regular HTTP servers, the second approach leads to deeper integration with the GraphQL Engine, providing more flexibility and control.

Note: You could also implement auth directly in your business logic but this is generally a bad idea.

These two approaches are widely recommended but the concrete examples out there are pretty basic. Like those simple username/password authentication using bcrypt types of examples. These are good but when you start thinking about use cases like user management, third party login and single sign on you will find that these are really hard to implement well. In corporate enterprise environments, a more comprehensive solution is needed.

Keycloak

That’s where Keycloak comes in. Keycloak is the leading Open Source identity and access management solution that provides many features suited to enterprise needs.

  • User Management
  • Single Sign On
  • Identity Brokering and Social Login (example: Google, Twitter, Facebook Logins)
  • User Federation (LDAP and Active Directory)

Keycloak is deployed as a 3rd party service with client and server side libraries that do the heavy lifting for you.

  • keycloak-connect is an Express middleware that adds authentication and authorization to your Node.js backend.
  • keycloak-js is a JavaScript adapter that helps you implement and manage your auth flows on the client side.

keycloak-connect by itself will help you achieve authentication at the HTTP level. However, more work was needed to achieve it at a GraphQL level. That’s how we ended up developing keycloak-connect-graphql.

Introducing keycloak-connect-graphql

keycloak-connect-graphql is a comprehensive solution for adding Keycloak authentication and authorization to your Express based GraphQL server. It is used alongside keycloak-connect to provide useful auth features at the GraphQL level.

🔒 Auth at the GraphQL layer. Authentication and Role Based Access Control (RBAC) on individual Queries, Mutations and fields.

⚡️ Auth on Subscriptions. Authentication and RBAC on incoming websocket connections for subscriptions.

🔑 Access to token/user information in resolver context via `context.kauth` (for regular resolvers and subscriptions).

📝 Declarative @auth and @hasRole directives that can be applied directly in your Schema.

⚙️ auth and hasRole middleware resolver functions that can be used directly in code (alternative to directives).

Getting Started

There are 3 steps to set up keycloak-connect-graphql in your application.

  1. Add the KeycloakTypeDefs along with your own type defs.
  2. Add the KeycloakSchemaDirectives (Apollo Server).
  3. Add the KeycloakContext to context.kauth.

The example below shows a typical setup with comments beside each of the 3 steps mentioned.

keycloak.middleware() parses user token information from requests, but will not block unauthenticated requests. This approach gives us the flexibility to implement authentication at a GraphQL level on individual Queries, Mutations and Fields.

The @auth and @hasRole Directives

The @auth and @hasRole directives can be used directly on the schema.
This declarative approach means auth logic is never mixed with business logic.

Check out the example schema and resolvers below.

A number of things are happening.

  1. @auth is applied to the `listArticles` Query. This means a user must be authenticated for this Query.
  2. @hasRole(role: “editor”) is applied to the publishArticle Mutation. This means the Keycloak user must have the editor client role in Keycloak. An array of roles can be passed if needed.
  3. The publishArticle resolver shows how context.kauth can be used to get the Keycloak user details.

Note: you can use @auth and @hasRole on any field. For example, imagine if the Article type had an extra field that was sensitive.

type Article {
id: ID!
title: String!
content: String!
analytics: !ArticleAnalytics @hasRole(role: “editor”)
}

In this case, @hasRole will be enforced for any query, mutation or subscription where the client asks for that field. This is very powerful!

Some GraphQL environments do not support directives. In that case, you can use the auth and hasRole implementations directly at the resolver level.

This “middleware” type approach still keeps a clean separation between the auth logic and the actual business logic.

Authentication and Authorization on Subscriptions

SubscriptionServer has an onConnect function which can be used to validate incoming websocket connections. The KeycloakSubscriptionHandler does this and adds the Keycloak user token to the context in subscription resolvers.

In this example, the connectionParams are parsed into a Keycloak token. By returning { kauth: new KeycloakSubscriptionContext } we will have access to the token in our subscription resolvers (via context.kauth).

If invalid connectionParams or an expired/invalid Keycloak token is supplied, an error is thrown and the subscription is cancelled. This is an easy way to force authentication on all subscriptions.

You can also do auth on a more granular level in your subscription resolvers.

Check the README for more detail.

On the client side, The Keycloak token can be passed as part of the initial websocket connection. The example below shows how it can be done with Apollo Client.

See the Apollo Client documentation for Authentication Params Over Websocket for more information.

Working Examples

The keycloak-connect-graphql repo also has several working example servers that you can use to see the features in action and to get sample code.

Starting and configuring a Keycloak server locally can be quite tricky and time consuming. The included scripts in the repo make it very simple! We invite you to try the examples out and of course, feedback and contributions are very welcome!

--

--

Dara Hayes

Software Engineer doing Open Source at Red Hat and playing music in my free time. https://darahayes.com