Using Nuxt 3. Currently I can parse a JWT in the server middleware to get the logged in user, but I want to save that logged in user info to a global variable. Then, on the client side I want to get that logged in user.
In the environment where my Nuxt web app will be hosted, authentication happens at the infrastructure level (K8s), so I don't really need to implement OAuth mechanisms. I just need to parse the JWT from the request header.
I've been reading into the Nuxt context but I'm still confused about how to actually implement it. Do you recommend this approach, or something else like an auth library?
Using Nuxt 3. Currently I can parse a JWT in the server middleware to get the logged in user, but I want to save that logged in user info to a global variable. Then, on the client side I want to get that logged in user.
In the environment where my Nuxt web app will be hosted, authentication happens at the infrastructure level (K8s), so I don't really need to implement OAuth mechanisms. I just need to parse the JWT from the request header.
I've been reading into the Nuxt context but I'm still confused about how to actually implement it. Do you recommend this approach, or something else like an auth library?
I think the best approach for your use case is to use a composable to manage the user state in conjunction with a server plugin. Here's an example:
interface User {
// define the shape you expect from the token
sub: string
email?: string
}
export const useAuth = () => {
// Create a global state named 'user'.
// Nuxt automatically serializes this state from SSR to client.
return useState<User | null>('user', () => null)
}
And then have a plugin that runs on server to read the token from Authorization header and fill the user state in the store, like below:
import { parse } from 'some-jwt-library'
import { getHeader } from 'h3' // <-- make sure to import from h3
export default defineNuxtPlugin((nuxtApp) => {
const event = useRequestEvent()
const token = getHeader(event, 'Authorization')
if (!token) return
const user = useState('user', () => null)
// parse token...
user.value = parse(token)
})
and then in your .vue files you can use it like this:
<script setup lang="ts">
import {useAuth} from "~/composables/useAuth";
const user = useAuth()
</script>
<template>
<div>
Hello: {{ user }}
</div>
</template>
I solved this using @fernando-del-cantão suggestion:
composables/useAuth.ts
interface User {
// define the shape you expect from the token
sub: string
email?: string
}
export const useAuth = () => {
// Create a global state named 'user'.
// Nuxt automatically serializes this state from SSR to client.
return useState<User | null>('user', () => null)
}
server/middleware/auth.ts
import { jwtDecode } from "jwt-decode";
export default defineEventHandler((event) => {
const headers = getRequestHeaders(event)
const token = headers[config.awsHeaderName]
event.context.user = jwtDecode(token);
})
plugins/auth.server.ts
import { parse } from 'some-jwt-library'
import { getHeader } from 'h3' // <-- make sure to import from h3
export default defineNuxtPlugin((nuxtApp) => {
const event = useRequestEvent()
const token = getHeader(event, 'Authorization')
if (!token) return
const user = useState('user', () => null)
// parse token...
user.value = parse(token)
})
app.vue
<script setup lang="ts">
import {useAuth} from "~/composables/useAuth";
const user = useAuth()
</script>
<template>
<div>
Hello: {{ user }}
</div>
</template>
This works for now. I know there is more I can do, such as create a session using an auth library.
Credit to @fernando-del-cantão on helping me figure this out.