DEV Community

Cover image for Implementing OpenID Connect (OIDC) Authentication with Nuxt 3

Implementing OpenID Connect (OIDC) Authentication with Nuxt 3

Welker Arantes Ferreira on January 30, 2023

Intro Recently i started migrating an application from Nuxt 2 to Nuxt 3, but when i faced the authentication part i got a little lost si...
Collapse
 
kingside88 profile image
Kingside88 • • Edited

Thank you for your're tutorial.
For now I am strugeling to implement it because in this file:
// /middleware/auth.global.ts
It redirects me the whole time. Because the user is always null.
if (!user && !authFlowRoutes.includes(to.path)) {
services.$auth.signInRedirect()
} else {
authStore.setUpUserCredentials(user)
}

I use keycloak for this and implemented it with KeycloakJs and sidebase/nuxt-auth. But I would prefer to use it server side.
If someone is interested in Nuxt3 with KeycloakJs, you could check my ready to go demo: github.com/Kingside88/nuxt3-primev...

Any chance you could provide a demo Github repo?

Collapse
 
taikio profile image
Welker Arantes Ferreira •

Hi,

I will provide a Github repo as soon as possible

Collapse
 
kingside88 profile image
Kingside88 •

I did it for you, if you want you can begin there.
But in the example I get the error: window is not defined

Image description
github.com/Kingside88/nuxt3-oidc-c...

Thread Thread
 
taikio profile image
Welker Arantes Ferreira •

I published an example project on my Github, you can access it through this link: github.com/taikio/nuxt-3-oidc-auth

Collapse
 
mauricio_andrade profile image
Maurício Andrade Albuquerque •

I wrote another article with some modifications:

Collapse
 
radonyizsolt profile image
Zsolt Rádonyi •

Hi!
I am having a small trouble with this. I am trying to get the user profile data in my components, but it seems like when I first login for a short time it is not available yet. Once I refresh everything is available. Is there any way I can make sure that the authStore.setUpUserCredentials is finished before the middleware let's it through?

Thank you!

Collapse
 
victorneves profile image
Victor Neves •

Hi Welker

There is any way to make this work also with SSR?

Thanks

Collapse
 
gavinie profile image
GavinIE •

Hi Welker, thanks for the article. Did you ever switch to using environment variables? I am struggling to get that working correctly. Thanks

Collapse
 
taikio profile image
Welker Arantes Ferreira •

Hi Gavin,

To use environment variables in Nuxt 3 you need to follow these steps:

1 - create an .env file with the environment variables. Ex:

BASE_URL=http://api.identity-server.com
Enter fullscreen mode Exit fullscreen mode

2 - in the nuxt.config file you need to set the values ​​inside the runtimeConfig property. By default these values ​​are only accessible on the server side, if you want to access the values ​​in Vuejs components define them inside the public property.
EX:

export default defineNuxtConfig({
  runtimeConfig: {
    baseUrl: process.env.BASE_URL,
    public: {
      publicValue: ' '
    }
  }
})
Enter fullscreen mode Exit fullscreen mode

3 - In the Vuejs component or in the endpoint access the values ​​through the composable useRuntimeConfig.
Ex:

const config = useRuntimeConfig()
Enter fullscreen mode Exit fullscreen mode

For more detailed information take a look at the official Nuxt documentation:

nuxt.com/docs/api/composables/use-...

Collapse
 
gavinie profile image
GavinIE •

Thanks very much. I have it configured like this currently and was just wondering if there was a way to implement this solution without needing to place that information in the public runtimeConfig.

I will keep looking and check in if I find a way to move that config to a more secure place.

Thread Thread
 
taikio profile image
Welker Arantes Ferreira •

In my case, to make it safer, I did it like this:

1 - I created an endpoint within the Nuxt project itself and check if there is a Secret Key in the request header:

// /server/api/settings.ts
import { sendError, createError } from "h3";

export default defineEventHandler((event) => {
  const authorizationHeader = getHeader(event, "authorization");

  if (
    !authorizationHeader ||
    authorizationHeader !== "SECRET_KEY"
  ) {
    return sendError(
      event,
      createError({ statusCode: 401, statusMessage: "Missing API key" })
    );
  }

  const runtimeConfig = useRuntimeConfig();

  return runtimeConfig;
});
Enter fullscreen mode Exit fullscreen mode

2 - I created a service to fetch this data. Then I make the request in the application startup middleware and store it in the store:

// /services/settings/index.ts
import { ISettings } from "./types";

export default class SettingsService {
  private apiKey: string;

  constructor() {
    this.apiKey = "SECRET_KEY";
  }

  async get(): Promise<ISettings> {
    const headers = { authorization: this.apiKey };

    const result = await $fetch<ISettings>("/api/settings", {
      method: "get",
      headers,
    });

    return result;
  }
}
Enter fullscreen mode Exit fullscreen mode
// /middleware/auth-middleware.global.ts
export default defineNuxtRouteMiddleware(async (to, _from) => {
    ...
    const settings = await services.$settings.get()
    settingsStore.setSettings(settings)
})
Enter fullscreen mode Exit fullscreen mode