From 4729b1fab03d76ce6f815a95e9d3a7173a5fc276 Mon Sep 17 00:00:00 2001 From: Alexander Date: Thu, 8 Aug 2024 14:37:28 +0500 Subject: [PATCH] feat(#836)!: unification and flexibility with `AUTH_ORIGIN` (#837) * feat!: unification and flexibility with `AUTH_ORIGIN` * docs: using `AUTH_ORIGIN` * chore: rebuild with pnpm@6 * fix: extracting a variable from ENV * docs: update `originEnvKey` type description Co-authored-by: Marsel Shayhin <18054980+phoenix-ru@users.noreply.github.com> * fix: install scule after resolve conflicts * Update docs/guide/application-side/configuration.md Co-authored-by: Marsel Shayhin <18054980+phoenix-ru@users.noreply.github.com> * fix: broken lock after resolve conflict * Update src/runtime/server/services/utils.ts Co-authored-by: Marsel Shayhin <18054980+phoenix-ru@users.noreply.github.com> * fix: typecheck * Update docs/resources/error-reference.md Co-authored-by: Zoey --------- Co-authored-by: Marsel Shayhin <18054980+phoenix-ru@users.noreply.github.com> Co-authored-by: Zoey --- docs/guide/advanced/deployment/self-hosted.md | 8 +- docs/guide/application-side/configuration.md | 8 ++ docs/resources/error-reference.md | 14 +- package.json | 1 + pnpm-lock.yaml | 129 ++++++++++++++++-- src/module.ts | 1 + src/runtime/server/services/utils.ts | 11 +- src/runtime/types.ts | 9 ++ 8 files changed, 162 insertions(+), 19 deletions(-) diff --git a/docs/guide/advanced/deployment/self-hosted.md b/docs/guide/advanced/deployment/self-hosted.md index 59d888ce..3e885a3f 100644 --- a/docs/guide/advanced/deployment/self-hosted.md +++ b/docs/guide/advanced/deployment/self-hosted.md @@ -6,7 +6,7 @@ This guide will explain how you can self-host a Nuxt3 application running NuxtAu When deploying the Auth.JS provider, the application must be informed what URL it is running at. This is to properly determine callback urls when navigating users to external OAuth providers. Depending on your setup, NuxtAuth allows you to set this value at either [**Runtime**](https://nuxt.com/docs/guide/going-further/hooks#app-hooks-runtime) or [**Buildtime**](https://nuxt.com/docs/guide/going-further/hooks#nuxt-hooks-build-time). -- **Runtime:** Set the `AUTH_ORIGIN` environment variable. +- **Runtime:** Set the `NUXT_AUTH_ORIGIN` environment variable. - **Buildtime:** Set the `baseURL`-config key inside the `nuxt.config.ts` The origin consists out of: @@ -15,17 +15,17 @@ The origin consists out of: - **host:** e.g., localhost, example.org, google.com - **port:** empty (implies `:80` for http and `:443` for https), :3000, :8888 -An example of the `AUTH_ORIGIN` would be: `https://my-awesome-app.com` +An example of the `NUXT_AUTH_ORIGIN` would be: `https://my-awesome-app.com` :::info Origin Order When [attempting to determine the server origin](https://github.com/sidebase/nuxt-auth/blob/main/src/runtime/server/services/utils.ts#L11), NuxtAuth checks the available options in the following order: -- **Prio 1**: Using `AUTH_ORIGIN` +- **Prio 1**: Using `NUXT_AUTH_ORIGIN` - **Prio 2**: Using `baseURL`-config key from inside the `nuxt.config.ts` - **Prio 3**: Infer the origin _(Only in development)_ ::: :::tip -We recommend setting the `AUTH_ORIGIN` during runtime and leaving the `baseURL`-config key empty, to avoid using a potentially incorrect ORIGIN. +We recommend setting the `NUXT_AUTH_ORIGIN` during runtime and leaving the `baseURL`-config key empty, to avoid using a potentially incorrect ORIGIN. ::: In addition to verifying that the origin is correctly set, also ensure that you have a secure [`secret` set in the NuxtAuthHandler](/guide/authjs/nuxt-auth-handler#secret). diff --git a/docs/guide/application-side/configuration.md b/docs/guide/application-side/configuration.md index 0505eec6..299f1a19 100644 --- a/docs/guide/application-side/configuration.md +++ b/docs/guide/application-side/configuration.md @@ -8,6 +8,7 @@ export default defineNuxtConfig({ auth: { isEnabled: true, disableServerSideAuth: false, + originEnvKey: 'AUTH_ORIGIN', baseURL: 'http://localhost:3000/api/auth', provider: { /* your provider config */ }, sessionRefresh: { @@ -25,6 +26,13 @@ export default defineNuxtConfig({ Whether the module is enabled at all +## `originEnvKey` + +- **Type**: `string` +- **Default**: `AUTH_ORIGIN` + +The name of the environment variable that holds the origin of the application. This is used to determine the origin of your application in production. Read more [here](/resources/error-reference#auth-no-origin). + ## `disableServerSideAuth` - **Type**: `boolean` diff --git a/docs/resources/error-reference.md b/docs/resources/error-reference.md index 0f4e4208..9a6d86b1 100644 --- a/docs/resources/error-reference.md +++ b/docs/resources/error-reference.md @@ -21,8 +21,18 @@ export default NuxtAuthHandler({ `AUTH_NO_ORIGIN` will appear as a warning message during development and be thrown as an error that stops the application during production. It is safe to ignore the development warning - it is only meant as a heads-up for your later production-deployment. `AUTH_NO_ORIGIN` occurs when the origin of your application was not set. NuxtAuth tries to find the origin of your application in the following order: -1. Use the `AUTH_ORIGIN` environment variable if it is set, +1. Use the `NUXT_AUTH_ORIGIN` environment variable if it is set 2. Development only: Determine the origin automatically from the incoming HTTP request - The `origin` is important for callbacks that happen to a specific origin for `oauth` flows. Note that in order for (2) to work the `origin` already has to be set at build-time, i.e., when you run `npm run build` or `npm run generate` and it will lead to the `origin` being inside your app-bundle. + +```ts +// file: nuxt.config.ts +export default defineNuxtConfig({ + runtimeConfig: { + authOrigin: 'https://example.org', // You can either set a default or leave it empty + } + + // ... rest of your config +}) +``` diff --git a/package.json b/package.json index 5b777a53..8ada0743 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "knitwork": "^1.1.0", "nitropack": "^2.9.7", "requrl": "^3.0.2", + "scule": "^1.3.0", "ufo": "^1.5.4" }, "peerDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a6aef68f..607b421a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,6 +29,9 @@ importers: requrl: specifier: ^3.0.2 version: 3.0.2 + scule: + specifier: ^1.3.0 + version: 1.3.0 ufo: specifier: ^1.5.4 version: 1.5.4 @@ -74,7 +77,7 @@ importers: version: 8.57.0 nuxt: specifier: ^3.12.4 - version: 3.12.4(@parcel/watcher@2.4.1)(@types/node@20.12.7)(encoding@0.1.13)(eslint@8.57.0)(ioredis@5.4.1)(magicast@0.3.4)(optionator@0.9.3)(rollup@4.19.2)(terser@5.30.3)(typescript@5.5.4)(vite@5.3.5(@types/node@20.12.7)(terser@5.30.3))(vue-tsc@2.0.29(typescript@5.5.4)) + version: 3.12.4(@parcel/watcher@2.4.1)(@types/node@20.12.7)(encoding@0.1.13)(eslint@8.57.0)(ioredis@5.4.1)(magicast@0.3.4)(optionator@0.9.3)(rollup@4.19.2)(terser@5.30.3)(typescript@5.5.4)(vite@5.3.3(@types/node@18.19.42)(terser@5.30.3))(vue-tsc@2.0.29(typescript@5.5.4)) typescript: specifier: ^5.5.4 version: 5.5.4 @@ -6146,7 +6149,7 @@ snapshots: '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.25.2)': dependencies: '@babel/core': 7.25.2 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-plugin-utils': 7.24.8 '@babel/plugin-syntax-jsx@7.24.1(@babel/core@7.25.2)': dependencies: @@ -7860,7 +7863,7 @@ snapshots: '@vue/devtools-core@7.3.3(vite@5.3.3(@types/node@18.19.42)(terser@5.30.3))': dependencies: - '@vue/devtools-kit': 7.3.3 + '@vue/devtools-kit': 7.3.5 '@vue/devtools-shared': 7.3.7 mitt: 3.0.1 nanoid: 3.3.7 @@ -7871,7 +7874,7 @@ snapshots: '@vue/devtools-core@7.3.3(vite@5.3.5(@types/node@18.19.42)(terser@5.30.3))': dependencies: - '@vue/devtools-kit': 7.3.3 + '@vue/devtools-kit': 7.3.5 '@vue/devtools-shared': 7.3.7 mitt: 3.0.1 nanoid: 3.3.7 @@ -7882,7 +7885,7 @@ snapshots: '@vue/devtools-core@7.3.3(vite@5.3.5(@types/node@20.12.7)(terser@5.30.3))': dependencies: - '@vue/devtools-kit': 7.3.3 + '@vue/devtools-kit': 7.3.5 '@vue/devtools-shared': 7.3.7 mitt: 3.0.1 nanoid: 3.3.7 @@ -9984,8 +9987,8 @@ snapshots: magicast@0.3.4: dependencies: - '@babel/parser': 7.24.4 - '@babel/types': 7.24.0 + '@babel/parser': 7.25.3 + '@babel/types': 7.25.2 source-map-js: 1.2.0 make-dir@3.1.0: @@ -10520,6 +10523,112 @@ snapshots: - vue-tsc - xml2js + nuxt@3.12.4(@parcel/watcher@2.4.1)(@types/node@20.12.7)(encoding@0.1.13)(eslint@8.57.0)(ioredis@5.4.1)(magicast@0.3.4)(optionator@0.9.3)(rollup@4.19.2)(terser@5.30.3)(typescript@5.5.4)(vite@5.3.3(@types/node@18.19.42)(terser@5.30.3))(vue-tsc@2.0.29(typescript@5.5.4)): + dependencies: + '@nuxt/devalue': 2.0.2 + '@nuxt/devtools': 1.3.9(rollup@4.19.2)(vite@5.3.3(@types/node@18.19.42)(terser@5.30.3)) + '@nuxt/kit': 3.12.4(magicast@0.3.4)(rollup@4.19.2) + '@nuxt/schema': 3.12.4(rollup@4.19.2) + '@nuxt/telemetry': 2.5.4(magicast@0.3.4)(rollup@4.19.2) + '@nuxt/vite-builder': 3.12.4(@types/node@20.12.7)(eslint@8.57.0)(magicast@0.3.4)(optionator@0.9.3)(rollup@4.19.2)(terser@5.30.3)(typescript@5.5.4)(vue-tsc@2.0.29(typescript@5.5.4))(vue@3.4.35(typescript@5.5.4)) + '@unhead/dom': 1.9.16 + '@unhead/ssr': 1.9.16 + '@unhead/vue': 1.9.16(vue@3.4.35(typescript@5.5.4)) + '@vue/shared': 3.4.35 + acorn: 8.12.1 + c12: 1.11.1(magicast@0.3.4) + chokidar: 3.6.0 + compatx: 0.1.8 + consola: 3.2.3 + cookie-es: 1.1.0 + defu: 6.1.4 + destr: 2.0.3 + devalue: 5.0.0 + errx: 0.1.0 + esbuild: 0.23.0 + escape-string-regexp: 5.0.0 + estree-walker: 3.0.3 + globby: 14.0.2 + h3: 1.12.0 + hookable: 5.5.3 + ignore: 5.3.1 + jiti: 1.21.6 + klona: 2.0.6 + knitwork: 1.1.0 + magic-string: 0.30.10 + mlly: 1.7.1 + nitropack: 2.9.7(encoding@0.1.13)(magicast@0.3.4) + nuxi: 3.12.0 + nypm: 0.3.9 + ofetch: 1.3.4 + ohash: 1.1.3 + pathe: 1.1.2 + perfect-debounce: 1.0.0 + pkg-types: 1.1.3 + radix3: 1.1.2 + scule: 1.3.0 + semver: 7.6.3 + std-env: 3.7.0 + strip-literal: 2.1.0 + ufo: 1.5.4 + ultrahtml: 1.5.3 + uncrypto: 0.1.3 + unctx: 2.3.1 + unenv: 1.10.0 + unimport: 3.9.1(rollup@4.19.2) + unplugin: 1.12.0 + unplugin-vue-router: 0.10.2(rollup@4.19.2)(vue-router@4.4.2(vue@3.4.35(typescript@5.5.4)))(vue@3.4.35(typescript@5.5.4)) + unstorage: 1.10.2(ioredis@5.4.1) + untyped: 1.4.2 + vue: 3.4.35(typescript@5.5.4) + vue-bundle-renderer: 2.1.0 + vue-devtools-stub: 0.1.0 + vue-router: 4.4.2(vue@3.4.35(typescript@5.5.4)) + optionalDependencies: + '@parcel/watcher': 2.4.1 + '@types/node': 20.12.7 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@biomejs/biome' + - '@capacitor/preferences' + - '@libsql/client' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/kv' + - better-sqlite3 + - bufferutil + - drizzle-orm + - encoding + - eslint + - idb-keyval + - ioredis + - less + - lightningcss + - magicast + - meow + - optionator + - rollup + - sass + - stylelint + - stylus + - sugarss + - supports-color + - terser + - typescript + - uWebSockets.js + - utf-8-validate + - vite + - vls + - vti + - vue-tsc + - xml2js + nuxt@3.12.4(@parcel/watcher@2.4.1)(@types/node@20.12.7)(encoding@0.1.13)(eslint@8.57.0)(ioredis@5.4.1)(magicast@0.3.4)(optionator@0.9.3)(rollup@4.19.2)(terser@5.30.3)(typescript@5.5.4)(vite@5.3.5(@types/node@20.12.7)(terser@5.30.3))(vue-tsc@2.0.29(typescript@5.5.4)): dependencies: '@nuxt/devalue': 2.0.2 @@ -12247,7 +12356,7 @@ snapshots: '@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.25.2) '@vue/compiler-dom': 3.4.35 kolorist: 1.8.0 - magic-string: 0.30.10 + magic-string: 0.30.11 vite: 5.3.3(@types/node@18.19.42)(terser@5.30.3) transitivePeerDependencies: - supports-color @@ -12262,7 +12371,7 @@ snapshots: '@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.25.2) '@vue/compiler-dom': 3.4.35 kolorist: 1.8.0 - magic-string: 0.30.10 + magic-string: 0.30.11 vite: 5.3.5(@types/node@18.19.42)(terser@5.30.3) transitivePeerDependencies: - supports-color @@ -12277,7 +12386,7 @@ snapshots: '@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.25.2) '@vue/compiler-dom': 3.4.35 kolorist: 1.8.0 - magic-string: 0.30.10 + magic-string: 0.30.11 vite: 5.3.5(@types/node@20.12.7)(terser@5.30.3) transitivePeerDependencies: - supports-color diff --git a/src/module.ts b/src/module.ts index 2b271672..cfa29c37 100644 --- a/src/module.ts +++ b/src/module.ts @@ -27,6 +27,7 @@ import type { const topLevelDefaults = { isEnabled: true, disableServerSideAuth: false, + originEnvKey: 'AUTH_ORIGIN', sessionRefresh: { enablePeriodically: false, enableOnWindowFocus: true, diff --git a/src/runtime/server/services/utils.ts b/src/runtime/server/services/utils.ts index 8a8f3c5b..17a34bfe 100644 --- a/src/runtime/server/services/utils.ts +++ b/src/runtime/server/services/utils.ts @@ -1,6 +1,7 @@ import { H3Event } from 'h3' import getURL from 'requrl' import { joinURL } from 'ufo' +import { camelCase } from 'scule' import { isProduction } from '../../helpers' import { ERROR_MESSAGES } from './errors' import { useRuntimeConfig } from '#imports' @@ -9,14 +10,18 @@ import { useRuntimeConfig } from '#imports' * Get `origin` and fallback to `x-forwarded-host` or `host` headers if not in production. */ export const getServerOrigin = (event?: H3Event): string => { + const config = useRuntimeConfig() + // Prio 1: Environment variable - const envOrigin = process.env.AUTH_ORIGIN + const envOriginKey = config.public.auth.originEnvKey! + const envOriginKeyCamelcase = camelCase(envOriginKey, { normalize: true }) + const envOrigin = (config[envOriginKeyCamelcase] ?? process.env[envOriginKey]) as string | undefined if (envOrigin) { return envOrigin } - // Prio 2: Runtime configuration - const runtimeConfigOrigin = useRuntimeConfig().public.auth.computed.origin + // Prio 2: Computed origin + const runtimeConfigOrigin = config.public.auth.computed.origin if (runtimeConfigOrigin) { return runtimeConfigOrigin } diff --git a/src/runtime/types.ts b/src/runtime/types.ts index 61954bbb..29dc73e8 100644 --- a/src/runtime/types.ts +++ b/src/runtime/types.ts @@ -405,6 +405,15 @@ export interface ModuleOptions { * @default false */ disableServerSideAuth?: boolean; + /** + * The name of the environment variable that holds the origin of the application. This is used to determine the full URL of the application in production. + * As an example, if you set `NUXT_AUTH_ORIGIN=http://example.org` in your `.env` file, the module will use this to determine the full URL of the application. + * + * Find more about this in the documentation: https://auth.sidebase.io/resources/error-reference#auth-no-origin + * + * @default 'AUTH_ORIGIN' + */ + originEnvKey?: string /** * Full url at which the app will run combined with the path to authentication. You can set this differently depending on your selected authentication-provider: * - `authjs`: You must set the full URL, with origin and path in production. You can leave this empty in development