atinux / nuxt-auth-utils

Add Authentication to Nuxt applications with secured & sealed cookies sessions.
MIT License
973 stars 91 forks source link

Question: Dynamic OAuth providers activation post-build for self-hosting scenarios #277

Open HugoRCD opened 1 week ago

HugoRCD commented 1 week ago

Context

When self-hosting a Nuxt application with Docker, it would be valuable to enable/disable OAuth providers without rebuilding the image, simply by providing/removing environment variables in docker-compose.yml.

Feature Request

Would it be possible to make OAuth providers configuration truly dynamic?

The goal would be to:

This would greatly improve flexibility for self-hosted deployments, allowing users to configure their authentication methods through environment variables alone.

Example use case:


# Enable only GitHub OAuth
services:
  app:
    environment:
      - NUXT_OAUTH_GITHUB_CLIENT_ID=xxx
      - NUXT_OAUTH_GITHUB_CLIENT_SECRET=xxx

# Later, enable Google OAuth by just adding variables
services:
  app:
    environment:
      - NUXT_OAUTH_GITHUB_CLIENT_ID=xxx
      - NUXT_OAUTH_GITHUB_CLIENT_SECRET=xxx
      - NUXT_OAUTH_GOOGLE_CLIENT_ID=xxx
      - NUXT_OAUTH_GOOGLE_CLIENT_SECRET=xxx
atinux commented 1 week ago

Hi @HugoRCD

As the server helpers are tree-shakable for maximum performance and minimum server bundle size, you will have to import then and create your own dynamic provider server endpoint.

Please see an example on how to achieve this by creating a /auth/:provider endpoint:

// server/routes/auth/[provider].get.ts
import { z } from 'zod'
import { defineOAuthGitHubEventHandler, defineOAuthGoogleEventHandler } from '#imports'

const oAuthEventHandlers = {
  github: defineOAuthGitHubEventHandler,
  google: defineOAuthGoogleEventHandler
}

export default defineEventHandler(async (event) => {
  // Validate the provider
  const { provider } = await getValidatedRouterParams(event, z.object({
    provider: z.enum(['github', 'google'])
  }).parse)

  // Make sure the provider client id and secret are set
  const providerConfig = useRuntimeConfig(event).oauth[provider]
  if (!providerConfig.clientId || !providerConfig.clientSecret) {
    throw createError({
      statusCode: 400,
      statusMessage: `OAuth ${provider} is not configured`
    })
  }

  return oAuthEventHandlers[provider]({
    config: {
      // extra config for the provider
    },
    onSuccess(event, { user, tokens }) {
      // You code to handle for providers
    },
    onError(event, error) {
      // You code to handle for providers
    }
  })(event)
})
HugoRCD commented 1 week ago

Ok thanks, I'll try that then!