Intermediate

Table of Contents

  • SSR, Hybrid, Generate - Authentication per Mode
  • Option 1: Integration with nuxt-auth-utils - New and improved
  • Option 2: Integration with @sidebase/nuxt-auth - Battle-tested and ready to use
  • Conclusion: nuxt-auth-utils or @sidebase/nuxt

Meet the Author

Blueshoe uses Keycloak for authentication in many Nuxt applications. When selecting the right Nuxt module, we paid special attention to developer and user-friendliness.
Last updated:2025-10-10

NuxtVue.jsKeycloak


2💬
1🎉
1🚀

2025-10-10

User Authentication for Nuxt Applications with KeycloakNuxt & Keycloak: A Simple Guide to SSR Integration

Integrating Keycloak into a Nuxt application for robust authentication can be a challenge, especially with regard to Server-Side Rendering (SSR). In this article, we compare two leading modules, nuxt-auth-utils and @sidebase/nuxt-auth, and provide a step-by-step guide to help you choose the right solution.

Nuxt and Keycloak

Prerequisites

You should have the following knowledge to use the article optimally:

If you have any questions or if anything is unclear, feel free to use the comment function below the article.

SSR, Hybrid, Generate - Authentication per Mode

First, it's important to identify the mode in which the Nuxt application is running. This determines the different requirements for authentication. A blog article on the different modes can be found here.

Server-Side Rendering - If user information such as permissions, names, etc., is processed during server-side rendering, the Nitro server needs access to it. Accordingly, the Nitro/Nuxt server must be able to validate whether a session is authenticated or authorized.

Client-Side Rendering - There is no server logic. Everything is processed on the client-side (the browser) - accordingly, the handling of user information/session also runs exclusively on the client-side.

Hybrid-Rendering - Depending on whether the SSR routes require user session information or not, the Keycloak integration must be considered.

Option 1: Integration with nuxt-auth-utils - New and improved

Integrating Keycloak and Nuxt with nuxt-auth-utils could hardly be simpler. A little configuration in nuxt.config.js and the basic framework is ready:

runtimeConfig: {
    oauth: {
      keycloak: {
        serverUrl: 'https://keycloak.blueshoe.io',
        realm: 'Blueshoe',
        clientId: 'blueshoe-website',
        // clientSecret: '',
        redirectURL: 'https://blueshoe.io/auth/keycloak',
      },
    },
  },
  modules: [
    'nuxt-auth-utils',
  ]

Now, convenient Composables are available:

const { loggedIn, user, session, fetch, clear, openInPopup } = useUserSession()

With this information, user-specific information can be rendered quickly and easily:

<template>
  <span v-if="loggedIn">Hello, {{ user.firstName }} {{ user.lastName }}span>
  <span v-else>Hello Guestspan>
template>

Likewise, useful utils are available on the SSR side. If a route absolutely requires a valid user session, this can be easily achieved with the following composable:

const session = await requireUserSession(event)

So far, so good - but how does the login work?

Through the environment variables, the nuxt-auth-utils module has all the information available to generate the login redirect and to use the session on the redirect back to the Nuxt application.

💡 Note: The runtimeConfig is not an environment variable itself, but the way Nuxt provides access to environment variables. More on this in the Nuxt documentation.

For this, a server-side route is simply created under server/auth/keycloak.get.ts:

export default defineOAuthKeycloakEventHandler({
  async onSuccess(event, { user }) {
    await setUserSession(event, {
      user: {
        keycloak: user.preferred_username,
      },
      loggedInAt: Date.now(),
    })

    return sendRedirect(event, '/')
  },
})

If you now call /auth/keycloak/, you will be automatically redirected to the running Keycloak instance and receive a session after a successful login.

The module is by Sébastien Chopin - the creator of Nuxt himself - and has a solid standing with (as of Sep 2025) 95,000 downloads per month, regular updates, and 1,400 stargazers, and can be recommended with confidence.

Option 2: Integration with @sidebase/nuxt-auth - Battle-tested and ready to use

Another way to bring Nuxt and Keycloak together is the @sidebase/nuxt-auth package. With a few adjustments in nuxt.config.js, the module can be easily configured:

runtimeConfig: {
    public: {
      authOrigin: 'http://localhost:3000',
    },
  },

  modules: [
    '@sidebase/nuxt-auth',
  ],

  auth: {
    isEnabled: true,
    disableServerSideAuth: false,
    provider: {
      type: 'authjs',
      trustHost: false,
      defaultProvider: 'keycloak',
      addDefaultCallbackUrl: true,
    },
    sessionRefresh: {
      enablePeriodically: true,
      enableOnWindowFocus: true,
    },
  },

As the configuration already shows, @sidebase/nuxt-auth takes care of refreshing the session automatically. Keycloak exists as a pre-configured provider. We create the following file at server/api/auth/[...].ts and configure the provider:

import KeycloakProvider from 'next-auth/providers/keycloak'
import { NuxtAuthHandler } from '#auth'

export default NuxtAuthHandler({
  secret: 'your-secret-here',
  providers: [
    KeycloakProvider.default({
      clientId: process.env.KEYCLOAK_ID,
      clientSecret: process.env.KEYCLOAK_SECRET,
      issuer: process.env.KEYCLOAK_ISSUER,
    })
  ]
})

It is important to note here that the URL to the Keycloak realm must be specified as the issuer: https://my-keycloak-domain.com/realms/My_Realm.

Additionally, callbacks can be defined to react to various events:

export default NuxtAuthHandler({
    ...
    callbacks: {
        /* on before signin */
        async signIn({ user, account, profile, email, credentials }) {
          return true
        },
        /* on redirect to another url */
        async redirect({ url, baseUrl }) {
          return baseUrl
        },
        /* on session retrieval */
        async session({ session, user, token }) {
          return session
        },
        /* on JWT token creation or mutation */
        async jwt({ token, user, account, profile, isNewUser }) {
          return token
        }
      }
})

@sidebase/nuxt-auth automatically creates a page that provides the login and integrates with the given providers.

The user's data is then available in the application as follows:

<script setup>
const {
  status,
  data,
  lastRefreshedAt,
  getCsrfToken,
  getProviders,
  getSession,
  signIn,
  signOut
} = useAuth()
script>

The status indicates whether the user is authenticated or not. data contains user-specific data.

The module is SSR compatible and allows rendering different information based on the session.

@sidebase/nuxt-auth is developed by sidebase and has established itself as a reliable solution for authentication in Nuxt applications. With a well-established company behind it and regular updates, it offers a solid foundation for production applications and can be recommended with confidence.

Conclusion: nuxt-auth-utils or @sidebase/nuxt

As is often the case, the devil is in the details of the use case. 😉 Both modules have a good track record regarding further development, the integration is simple, and the composables are very good.

If you want to customize the typical authentication pages yourself, @sidebase/nuxt-auth is more suitable. The module also comes with a configurable simple refresh logic for the user session. nuxt-auth-utils, on the other hand, "feels" a bit more lightweight. A request for automatic session refresh is still pending. However, this can usually be easily retrofitted yourself.

We can warmly recommend both modules and look forward to feedback on your experiences with Nuxt and Keycloak in the comments!

How did you "plug together" Nuxt and Keycloak? Are there better ways? What are your experiences with the modules?


Do you have questions or an opinion? With your GitHub account you can let us know...


These companies trust Team Blueshoe

  • Allgau
  • Allianz
  • Audi
  • Chip
  • Deutsches Museum
  • DieProduktMacher
  • Dom Perignon
  • Finanz
  • Haufe Lexware
  • Kaufland
  • Luma
  • Ofa
  • SWM
  • Travian
  • TUHH
  • Uni Augsburg
  • Winter Company