diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f0b72261..d0dd9904 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,4 +1,4 @@ -name: nodejs CI +name: CI on: push: diff --git a/.github/workflows/pkg.pr.new.yml b/.github/workflows/pkg.pr.new.yml new file mode 100644 index 00000000..b18c86b2 --- /dev/null +++ b/.github/workflows/pkg.pr.new.yml @@ -0,0 +1,41 @@ +name: Publish Commit +on: + push: + branches: + - '**' + tags: + - '!**' + pull_request: + +env: + NODE_VER: 22.5 + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20] + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - uses: pnpm/action-setup@v4 + name: Install pnpm + with: + run_install: false + + - name: Use Node.js ${{ env.NODE_VER }} + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VER }} + cache: 'pnpm' + + - name: Install deps + run: pnpm i + + - name: Build and pack + run: pnpm prepack + + - name: Publish package preview + run: pnpx pkg-pr-new publish --compact diff --git a/.npmrc b/.npmrc index c7f8ad58..e208a7b3 100644 --- a/.npmrc +++ b/.npmrc @@ -1,3 +1,4 @@ shamefully-hoist=true strict-peer-dependencies=false link-workspace-packages=true +ignore-workspace-root-check=true diff --git a/README.md b/README.md index 76ca6b74..ef7316bb 100644 --- a/README.md +++ b/README.md @@ -64,8 +64,7 @@ Then visit the [Quick Start documentation](https://auth.sidebase.io/guide/gettin `@sidebase/nuxt-auth` is a library with the goal of supporting authentication for any universal Nuxt 3 application. At the moment three providers are supported: - [`authjs`](https://auth.sidebase.io/guide/authjs/quick-start): for non-static apps that want to use [Auth.js / NextAuth.js](https://github.com/nextauthjs/next-auth) to offer the reliability & convenience of a 23k star library to the Nuxt 3 ecosystem with a native developer experience (DX) -- [`local`](https://auth.sidebase.io/guide/local/quick-start): for static pages that rely on an external backend with a credential flow for authentication. -- [`refresh`](https://auth.sidebase.io/guide/local/quick-start#refresh-token): for static pages that rely on an external backend with a credential flow and refresh tokens for authentication. +- [`local`](https://auth.sidebase.io/guide/local/quick-start): for static pages that rely on an external backend with a credential flow for authentication. The Local Provider also supports refresh tokens since `v0.9.0`. Read more [here](https://auth.sidebase.io/upgrade/version-0.9.0). You can find a full list of our features, as well as which provider supports each feature [on our docs](https://auth.sidebase.io/guide/getting-started/choose-provider). @@ -142,7 +141,6 @@ This module also has it's own playground: We have one playground per provider: - [`authjs`](./playground-authjs) - [`local`](./playground-local) -- [`refresh`](./playground-refresh) ##### How to test static Nuxt 3 apps? diff --git a/docs/.vitepress/routes/navbar.ts b/docs/.vitepress/routes/navbar.ts index fd2f0cef..c2de2a18 100644 --- a/docs/.vitepress/routes/navbar.ts +++ b/docs/.vitepress/routes/navbar.ts @@ -13,7 +13,7 @@ export const routes: DefaultTheme.Config['nav'] = [ link: '/guide/authjs/quick-start', }, { - text: 'Local / Refresh guide', + text: 'Local guide', link: '/guide/local/quick-start', }, ], @@ -25,6 +25,10 @@ export const routes: DefaultTheme.Config['nav'] = [ text: 'Overview', link: '/resources/overview', }, + { + text: 'Upgrade Guides', + link: '/upgrade', + }, { text: 'Recipes', link: '/recipes/introduction/welcome', @@ -40,8 +44,12 @@ export const routes: DefaultTheme.Config['nav'] = [ ], }, { - text: '0.8.0', + text: '0.9.1', items: [ + { + text: '0.8.2', + link: 'https://github.com/sidebase/nuxt-auth/tree/0.8.2/docs', + }, { text: '0.7.2', link: 'https://github.com/sidebase/nuxt-auth/tree/0.7.2/docs/content', diff --git a/docs/.vitepress/routes/sidebar/guide.ts b/docs/.vitepress/routes/sidebar/guide.ts index ce07216b..7e822a2d 100644 --- a/docs/.vitepress/routes/sidebar/guide.ts +++ b/docs/.vitepress/routes/sidebar/guide.ts @@ -69,7 +69,7 @@ export const routes: DefaultTheme.SidebarItem[] = [ ], }, { - text: 'Local / Refresh Provider', + text: 'Local Provider', base: '/guide/local', items: [ { diff --git a/docs/.vitepress/routes/sidebar/index.ts b/docs/.vitepress/routes/sidebar/index.ts index 91240e73..e54b7582 100644 --- a/docs/.vitepress/routes/sidebar/index.ts +++ b/docs/.vitepress/routes/sidebar/index.ts @@ -2,8 +2,10 @@ import type { DefaultTheme } from 'vitepress' import { routes as guideRoutes } from './guide' import { routes as recipesRoutes } from './recipes' +import { routes as upgradeRoutes } from './upgrade' export const routes: DefaultTheme.Config['sidebar'] = { '/guide': guideRoutes, - '/recipes': recipesRoutes + '/recipes': recipesRoutes, + '/upgrade': upgradeRoutes } diff --git a/docs/.vitepress/routes/sidebar/upgrade.ts b/docs/.vitepress/routes/sidebar/upgrade.ts new file mode 100644 index 00000000..b4945ed5 --- /dev/null +++ b/docs/.vitepress/routes/sidebar/upgrade.ts @@ -0,0 +1,18 @@ +import type { DefaultTheme } from 'vitepress' + +export const routes: DefaultTheme.SidebarItem[] = [ + { + text: 'Versions', + base: '/upgrade', + items: [ + { + text: 'Version 0.9.0', + link: '/version-0.9.0' + }, + { + text: 'Version 0.8.0', + link: '/version-0.8.0' + } + ], + }, +] diff --git a/docs/.vitepress/theme/components/Layout.vue b/docs/.vitepress/theme/components/Layout.vue index 905cf4a0..e726d834 100644 --- a/docs/.vitepress/theme/components/Layout.vue +++ b/docs/.vitepress/theme/components/Layout.vue @@ -8,10 +8,10 @@ const { Layout } = DefaultTheme // Banner Configuration const bannerConfig = { // Leave text empty to disable the banner - text: '✨ NuxtAuth v0.8.0 has been released! ✨', + text: '🚀 NuxtAuth v0.9.0 has been released!', button: { - href: 'https://github.com/sidebase/nuxt-auth/releases/tag/0.8.0', - text: 'View release notes', + href: '/upgrade/version-0.9.0', + text: 'View upgrade guide', }, } diff --git a/docs/guide/advanced/deployment/self-hosted.md b/docs/guide/advanced/deployment/self-hosted.md index cfdd6d64..02bb0be6 100644 --- a/docs/guide/advanced/deployment/self-hosted.md +++ b/docs/guide/advanced/deployment/self-hosted.md @@ -30,9 +30,9 @@ We recommend setting the `NUXT_AUTH_ORIGIN` during runtime and leaving the `base 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). -## Local / Refresh Provider +## Local Provider -When deploying a Local or Refresh -provider based app, you will only need to set the correct `baseURL` to your authentication backend. +When deploying a Local provider based app, you will only need to set the correct `baseURL` to your authentication backend. This path can either be: @@ -40,7 +40,7 @@ This path can either be: - **Absolute**: Pointing at a path inside an external application (e.g. `https://my-auth-backend/api`) :::warning -For the `local` and `refresh` providers, this value will need to be set at build time. This is required to support static applications. +For the `local` provider, this value will need to be set at build time. This is required to support static applications. For this, ensure that you either directly set the `baseURL` inside the `nuxt.config.ts`, or provide a build-time environment variable that overwrites the value inside the `nuxt.config.ts`. ::: diff --git a/docs/guide/application-side/configuration.md b/docs/guide/application-side/configuration.md index 13a09224..f1345781 100644 --- a/docs/guide/application-side/configuration.md +++ b/docs/guide/application-side/configuration.md @@ -62,7 +62,7 @@ The full url at which the app will run combined with the path to authentication. - **port**: _empty_ (implies `:80` for http and `:443` for https), :3000, :8888 - **path**: the path that directs to the location of your `NuxtAuthHandler` e.g. `/api/auth` -### `local` and `refresh` Providers +### `local` Provider Defaults to `/api/auth` for both development and production. Setting this is optional, if you set it you can set it to either: - just a path: Will lead to `nuxt-auth` using `baseURL` as a relative path appended to the origin you deploy to. Example: `/backend/auth` @@ -74,12 +74,12 @@ If you point to a different origin than the one you deploy to you likely have to ## `provider` -- **Type**: `ProviderAuthjs | ProviderLocal | ProviderRefresh` +- **Type**: `ProviderAuthjs | ProviderLocal` - **Default**: `undefined` Configuration of the authentication provider. Different providers are supported: - AuthJS: See [configuration options here](/guide/authjs/quick-start#configuration) -- Local / Refresh: See [configuration options here](/guide/local/quick-start) +- Local: See [configuration options here](/guide/local/quick-start) ## `sessionRefresh` diff --git a/docs/guide/application-side/session-access.md b/docs/guide/application-side/session-access.md index 7788554c..90cd821c 100644 --- a/docs/guide/application-side/session-access.md +++ b/docs/guide/application-side/session-access.md @@ -27,25 +27,12 @@ const { data, lastRefreshedAt, token, - getSession, - signUp, - signIn, - signOut -} = useAuth() -``` - -```ts [refresh] -const { - status, - data, - lastRefreshedAt, - token, + refreshToken, getSession, signUp, signIn, signOut, - refresh, - refreshToken + refresh } = useAuth() ``` @@ -86,7 +73,7 @@ const { data } = useAuth() ``` -### `token` +### `token` local only The fetched token that can be used to authenticate further requests. This could be e.g. a JWT-Bearer token. @@ -103,15 +90,15 @@ function useAPI() { } ``` -:::warning Local / Refresh Only -`token` is only avalible for the refresh and local providers! +:::warning Local Only +`token` is only avalible for the local provider! ::: ### `lastRefreshedAt` Time at which the session was last refreshed, either `undefined` if no refresh was attempted or a `Date` of the time the refresh happened. -### `getCsrfToken` +### `getCsrfToken` authjs only Returns the current Cross Site Request Forgery Token (CSRF Token) required to make POST requests (e.g. for signing in and signing out). @@ -121,7 +108,7 @@ You likely only need to use this if you are not using the built-in `signIn()` an `getCsrfToken` is only avalible for the authjs provider! ::: -### `getProviders` +### `getProviders` authjs only Get a list of all the configured OAuth providers. Useful for creating a [custom login page](/guide/authjs/custom-pages#sign-in-page). Returns an array of `Provider`. @@ -158,7 +145,7 @@ const { getSession } = useAuth() ``` -### `signUp` +### `signUp` local only ```ts // `credentials` are the credentials your sign-up endpoint expects, @@ -184,8 +171,8 @@ await signUp(credentials, undefined, { preventLoginFlow: true }) You can also pass the `callbackUrl` option to redirect a user to a certain page, after they completed the action. This can be useful when a user attempts to open a page (`/protected`) but has to go through external authentication (e.g., via their google account) first. ::: -:::warning Local / Refresh Only -`signUp` is only avalible for the refresh and local providers! +:::warning Local Only +`signUp` is only avalible for the local provider! ::: ### `signIn` @@ -257,12 +244,12 @@ const { signOut } = useAuth() You can also pass the `callbackUrl` option to redirect a user to a certain page, after they completed the action. This can be useful when a user attempts to open a page (`/protected`) but has to go through external authentication (e.g., via their google account) first. ::: -### `refreshToken` +### `refreshToken` local only The fetched refreshToken that can be used to obtain a new access token . E.g. a refreshToken looks like this: `eyDFSJKLDAJ0-3249PPRFK3P5234SDFL;AFKJlkjdsjd.dsjlajhasdji89034` -:::warning Refresh Only -`refreshToken` is only avalible for the refresh provider! +:::warning Local Only +`refreshToken` is only avalible for the local provider! ::: ### `refresh` @@ -297,43 +284,6 @@ lastRefreshedAt.value ``` ```ts [local] -const { - status, - loading, - data, - lastRefreshedAt, - token, - rawToken, - setToken, - clearToken -} = useAuthState() - -// Session status, either `unauthenticated`, `loading`, `authenticated` -status.value - -// Whether any http request is still pending -loading.value - -// Session data, either `undefined` (= authentication not attempted), `null` (= user unauthenticated), or session / user data your `getSession`-endpoint returns -data.value - -// Time at which the session was last refreshed, either `undefined` if no refresh was attempted or a `Date` of the time the refresh happened -lastRefreshedAt.value - -// The fetched token that can be used to authenticate future requests. E.g., a JWT-Bearer token like so: `Bearer eyDFSJKLDAJ0-3249PPRFK3P5234SDFL;AFKJlkjdsjd.dsjlajhasdji89034` -token.value - -// Cookie that containes the raw fetched token string. This token won't contain any modification or prefixes like `Bearer` or any other. -rawToken.value - -// Helper method to quickly set a new token (alias for rawToken.value = 'xxx') -setToken('new token') - -// Helper method to quickly delete the token cookie (alias for rawToken.value = null) -clearToken() -``` - -```ts [refresh] const { status, loading, @@ -362,24 +312,18 @@ lastRefreshedAt.value // The fetched token that can be used to authenticate future requests. E.g., a JWT-Bearer token like so: `Bearer eyDFSJKLDAJ0-3249PPRFK3P5234SDFL;AFKJlkjdsjd.dsjlajhasdji89034` token.value -// The fetched refreshToken that can be used to refresh the Token with refresh() methode. -refreshToken.value - // Cookie that containes the raw fetched token string. This token won't contain any modification or prefixes like `Bearer` or any other. rawToken.value -// Cookie that containes the raw fetched refreshToken string. -rawRefreshToken.value - // Helper method to quickly set a new token (alias for rawToken.value = 'xxx') setToken('new token') -// Helper method to quickly delete the token and refresh Token cookie (alias for rawToken.value = null and rawRefreshToken.value = null) +// Helper method to quickly delete the token cookie (alias for rawToken.value = null) clearToken() ``` ::: -:::warning Local and refresh providers: +:::warning Local provider: Note that you will have to manually call getSession from useAuth composable in order to refresh the new user state when using setToken, clearToken or manually updating rawToken.value: ::: diff --git a/docs/guide/getting-started/choose-provider.md b/docs/guide/getting-started/choose-provider.md index 094f5b49..7992a77e 100644 --- a/docs/guide/getting-started/choose-provider.md +++ b/docs/guide/getting-started/choose-provider.md @@ -6,33 +6,36 @@ aside: false To pick a provider you will first have to take into consideration the requirements of your use-case. In general one can say that picking: -- `authjs` is best suited for plug-and-play OAuth for established oauth-providers or magic-url based sign-ins -- `local` is best when you already have a backend that accepts username + password as a login or want to build a static application -- `refresh` if you would need to extend the functionality of the `local` provider, with a refresh token +- `authjs` is best suited for plug-and-play OAuth for established oauth-providers or magic-url based sign-ins. +- `local` is best when you already have a backend that accepts username + password as a login or want to build a static application. The Local Provider also supports refresh tokens since `v0.9.0`. + +:::warning Breaking change +In `v0.9.0` the `refresh` provider was integrated into the `local` provider. Read the [upgrade guide](/upgrade/version-0.9.0). +::: If you are still unsure, below are some tables to help you pick: ### Authentication Methods -| | authjs | local | refresh -|----------------------------------------------------------- |-------------------------------------: |-------: | ------: -| OAuth | ✅ (>50 providers) | ❌ | ❌ -| Magic URLs | ✅ | ❌ | ❌ -| Credentials / Username + Password flow | 🚧 (if possible: use `local` instead) | ✅ | ✅ -| Refresh tokens | ✅ | ❌ | ✅ +| | authjs provider | local provider +|----------------------------------------------------------- |-------------------------------------: |---------------: +| OAuth | ✅ (>50 providers) | ❌ +| Magic URLs | ✅ | ❌ +| Credentials / Username + Password flow | 🚧 (if possible: use `local` instead) | ✅ +| Refresh tokens | ✅ | ✅ ### Features -| | authjs | local | refresh -|----------------------------------------------------------- |-------------------------------------: |------: | ------: -| [`useAuth`-composable](/guide/application-side/session-access) to sign in/out, refresh a session, etc. | ✅ | ✅ | ✅ -| Session-management: auto-refresh, refresh on refocus, ... | ✅ | ✅ | ✅ -| Static apps ("nuxi generate") | ❌ | ✅ | ✅ -| [Guest mode](/guide/application-side/protecting-pages#guest-mode) | ✅ | ✅ | ✅ -| [App-side middleware](/guide/application-side/protecting-pages) | ✅ | ✅ | ✅ -| [Server-side middleware](/guide/authjs/server-side/session-access#endpoint-protection) | ✅ | ❌ | ❌ -| Pre-made login-page | ✅ (impacts bundle-size) | ❌ | ❌ -| Database-adapters, server-side callback-hooks | ✅ | ❌ | ❌ +| | authjs provider | local provider +|----------------------------------------------------------- |-------------------------------------: |------: +| [`useAuth`-composable](/guide/application-side/session-access) to sign in/out, refresh a session, etc. | ✅ | ✅ +| Session-management: auto-refresh, refresh on refocus, ... | ✅ | ✅ +| Static apps ("nuxi generate") | ❌ | ✅ +| [Guest mode](/guide/application-side/protecting-pages#guest-mode) | ✅ | ✅ +| [App-side middleware](/guide/application-side/protecting-pages) | ✅ | ✅ +| [Server-side middleware](/guide/authjs/server-side/session-access#endpoint-protection) | ✅ | ❌ +| Pre-made login-page | ✅ (impacts bundle-size) | ❌ +| Database-adapters, server-side callback-hooks | ✅ | ❌ ::: tip Still unsure what is best for you? Join our [Discord](https://discord.gg/VzABbVsqAc) and share your use case! diff --git a/docs/guide/local/quick-start.md b/docs/guide/local/quick-start.md index f390049d..0c2c6c66 100644 --- a/docs/guide/local/quick-start.md +++ b/docs/guide/local/quick-start.md @@ -1,12 +1,14 @@ -# Local / Refresh provider +# Local provider -This guide is for setting up `@sidebase/nuxt-auth` with the Local / Refresh Provider, which is best suited for when you already have a backend that accepts username + password as a login or want to build a static application. +This guide is for setting up `@sidebase/nuxt-auth` with the Local Provider, which is best suited for when you already have a backend that accepts username + password as a login or want to build a static application. The Local Provider also supports refresh tokens since `v0.9.0`. -The `refresh` provider is based on the `local` provider and extends its functionality by adding support for refresh tokens. +:::warning Breaking change +In `v0.9.0` the `refresh` provider was integrated into the `local` provider. Read the [upgrade guide](/upgrade/version-0.9.0). +::: ## Configuration -The entire configuration for the `local` and `refresh` providers is contained inside the `nuxt.config.ts`. Inside the `auth` options, set your provider to either `local` or `refresh`. In this example, we will configure the `local` provider, however the same configuration applies to the `refresh` provider as well. +The entire configuration for the `local` provider is contained inside the `nuxt.config.ts`. Inside the `auth` options, set your provider to `local`. ```ts export default defineNuxtConfig({ @@ -14,7 +16,7 @@ export default defineNuxtConfig({ auth: { baseURL: '/api/auth', // or an external url: (e.g. https://auth.example.com/api/auth) provider: { - type: 'local' // or 'refresh' + type: 'local' } } }) @@ -81,7 +83,7 @@ You cannot disable the `getSession` endpoint, as NuxtAuth internally uses it to ### Using an external backend -When using the `local` or `refresh` provider to access an external backend, please consider that the module will attempt to resolve the API endpoints by using internal Nuxt 3 relative URLs or an external call. +When using the `local` provider to access an external backend, please consider that the module will attempt to resolve the API endpoints by using internal Nuxt 3 relative URLs or an external call. To ensure that the module can properly identify that your endpoints point to an external URL, please ensure the following: @@ -108,28 +110,6 @@ export default defineNuxtConfig({ You can read more about the path resolving logic in `@sidebase/nuxt-auth` [here](https://github.com/sidebase/nuxt-auth/issues/782#issuecomment-2223861422). -### Refresh provider - -If you are using the refresh provider, you can additionally define a `refresh` endpoint, which will be used to refresh the access token upon expiry. - -```ts -export default defineNuxtConfig({ - auth: { - baseURL: '/api/auth', - provider: { - type: 'local', - endpoints: { - signIn: { path: '/login', method: 'post' }, - signOut: { path: '/logout', method: 'post' }, - signUp: { path: '/register', method: 'post' }, - getSession: { path: '/session', method: 'get' }, - refresh: { path: '/refresh', method: 'post' } // [!code ++] - } - } - } -}) -``` - ## Token The `local` and `refresh` providers are both based on exchanging access tokens with your backend. NuxtAuth expects an access token to be provided by the `signIn` endpoint, which will then be saved into the session to authenticate further requests to e.g. `getSession`. @@ -229,46 +209,78 @@ If set, the cookie will not be accessible from JavaScript. See the specification - **Type:** `boolean` - **Default:** `'false'` -## Refresh token +## Refresh -:::tip -This section only applies to applications using the `refresh` provider. -::: - -If using the `refresh` provider, a seperate `refreshToken` configuration can also be passed to configure how the refresh token is handled. +A seperate `refresh` configuration can also be passed to configure how the refresh token is handled. ```ts export default defineNuxtConfig({ - // Previous configuration auth: { provider: { type: 'local', - token: { - signInResponseTokenPointer: '/token', - type: 'Bearer', - cookieName: 'auth.token', - headerName: 'Authorization', - maxAgeInSeconds: 1800, - sameSiteAttribute: 'lax', - cookieDomain: 'sidebase.io', - secureCookieAttribute: false, - httpOnlyCookieAttribute: false, + refresh: { + isEnabled: true, + endpoint: { path: '/refresh', method: 'POST' }, + refreshOnlyToken: true, + token: { + signInResponseRefreshTokenPointer: '/refresh-token', + refreshRequestTokenPointer: 'Bearer', + cookieName: 'auth.token', + maxAgeInSeconds: 1800, + sameSiteAttribute: 'lax', + secureCookieAttribute: false, + cookieDomain: 'sidebase.io', + httpOnlyCookieAttribute: false, + } }, - refreshToken: { - signInResponseRefreshTokenPointer: '/refresh-token', - refreshRequestTokenPointer: 'Bearer', - cookieName: 'auth.token', - maxAgeInSeconds: 1800, - cookieDomain: 'sidebase.io', - secureCookieAttribute: false, - httpOnlyCookieAttribute: false, + } + } +}) +``` + +### `isEnabled` + +- **Type:** `boolean` +- **Default:** `false` + +If the local provider should make automatic `refresh` requests to retrieve a new new `token`. If `isEnabled` is set to: + +- `false`: The provider will behave like the `local` provider prior to `v0.9.0` +- `true`: The provider will behave like the `refresh` provider prior to`v0.9.0` + +### `endpoint` + +- **Type:** `boolean` +- **Default:** `{ path: '/refresh', method: 'post' }` + +The endpoint to which `refresh` requests are made. The configuration of the `refresh` endpoint matches the configuration of the other endpoints. Read more [here](#api-endpoints). + +```ts +export default defineNuxtConfig({ + auth: { + provider: { + type: 'local', + refresh: { + endpoint: { + path: '/refresh', + method: 'POST' + } } } } }) ``` -### `signInResponseRefreshTokenPointer` +### `refreshOnlyToken` + +- **Type:** `boolean` +- **Default:** `true` + +When refreshOnlyToken is set, only the `token` will be refreshed and the `refreshToken` will stay the same. (This is helpful when only the `login` endpoint returns a `refreshToken`) + +### `token` + +#### `signInResponseRefreshTokenPointer` - **Type:** `string` - **Default:** `'/refreshToken'` @@ -279,21 +291,21 @@ E.g., setting this to `/token/refreshToken` and returning an object like `{ toke This follows the JSON Pointer standard, see its RFC6901 here: https://www.rfc-editor.org/rfc/rfc6901 -### `refreshRequestTokenPointer` +#### `refreshRequestTokenPointer` - **Type:** `string` - **Default:** `'/refreshToken'` How to do a fetch for the refresh token. This is especially useful when you have an external backend signing tokens. Refer to this issue to get more information: https://github.com/sidebase/nuxt-auth/issues/635. -### `cookieName` +#### `cookieName` - **Type:** `string` - **Default:** `'auth.refresh-token'` It refers to the name of the property when it is stored in a cookie. -### `maxAgeInSeconds` +#### `maxAgeInSeconds` - **Type:** `number` - **Default:** `1800` @@ -302,38 +314,27 @@ Maximum age to store the authentication token for. After the expiry time the tok Note: Your backend may reject / expire the refreshToken earlier / differently. -### `cookieDomain` +#### `cookieDomain` - **Type:** `string` - **Default:** `''` The cookie domain. See the specification here: https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.3 -### `secureCookieAttribute` +#### `secureCookieAttribute` If set, the cookie will be only sent through `HTTPS` protocol. See the specification here : https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.5 - **Type:** `boolean` - **Default:** `'false'` -### `httpOnlyCookieAttribute` +#### `httpOnlyCookieAttribute` If set, the cookie will not be accessible from JavaScript. See the specification here : https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.6 - **Type:** `boolean` - **Default:** `'false'` -## `refreshOnlyToken` - -:::tip -This section only applies to applications using the `refresh` provider. -::: - -- **Type:** `boolean` -- **Default:** `true` - -When refreshOnlyToken is set, only the token will be refreshed - ## Pages Configure the path of the login-page that the user should be redirected to, when they try to access a protected page without being logged in. This page will also not be blocked by the global middleware. diff --git a/docs/upgrade/index.md b/docs/upgrade/index.md new file mode 100644 index 00000000..bf4b0bc1 --- /dev/null +++ b/docs/upgrade/index.md @@ -0,0 +1,6 @@ +--- +title: 'Redirecting' +editLink: false +--- + + diff --git a/docs/upgrade/version-0.8.0.md b/docs/upgrade/version-0.8.0.md new file mode 100644 index 00000000..677fe703 --- /dev/null +++ b/docs/upgrade/version-0.8.0.md @@ -0,0 +1,103 @@ +# Upgrade to 0.8.0 + +> This release contains breaking changes for **all providers**. + +## Installation + +::: code-group + +```bash [npm] +npm i -D @sidebase/nuxt-auth@^0.8.0 +``` + +```bash [pnpm] +pnpm i -D @sidebase/nuxt-auth^0.8.0 +``` + +```bash [yarn] +yarn add --dev @sidebase/nuxt-auth^0.8.0 +``` + +::: + +## Breaking Changes + +- `auth.session` renamed to `auth.sessionRefresh` + +```ts +// nuxt.config.ts + +export default defineNuxtConfig({ + modules: ['@sidebase/nuxt-auth'], + auth: { + session: { // [!code --] + enableRefreshOnWindowFocus: true, // [!code --] + enableRefreshPeriodically: 10000, // [!code --] + }, // [!code --] + sessionRefresh: { // [!code ++] + enableOnWindowFocus: true, // [!code ++] + enablePeriodically: 10000, // [!code ++] + }, // [!code ++] + } +}) +``` + +## RefreshHandler + +In [#715](https://github.com/sidebase/nuxt-auth/pull/715), we took the first step to improve the behavior and possibilities to customize the Refresh behaviour of your application. In [#766](https://github.com/sidebase/nuxt-auth/pull/766) we finalized these changes and improved the previous configuration options. You can define the location of a custom RefreshHandler inside your Nuxt config under `auth.sessionRefresh.refreshHandler`. + +To customize the session refreshing you can provide a refresh handler. A custom `RefreshHandler` requires an `init`- and a `destroy`-function. + +- `init` will be called when the nuxt application is mounted. Here you may add event listeners and initialize custom refresh behaviour. The method will receive a `RefreshHandlerConfig`. The type consists of `enablePeriodically` & `enableOnWindowFocus`. +- `destroy` will be called when your app is unmounted. Here you may run your clean up routine e.g. to remove your event listeners. + +```ts +import type { RefreshHandler } from '@sidebase/nuxt-auth' + +// You may also use a plain object with `satisfies RefreshHandler`, of course! +class CustomRefreshHandler implements RefreshHandler { + init(): void { + console.info('Use the full power of classes to customize refreshHandler!') + } + + destroy(): void { + console.info( + 'Hover above class properties or go to their definition ' + + 'to learn more about how to craft a refreshHandler' + ) + } +} + +export default new CustomRefreshHandler() +``` + +## Changelog + +* Feature: Option to remove server side auth by @KyleSmith0905 in https://github.com/sidebase/nuxt-auth/pull/610 +* docs: Added documentation for automatic session refresh by @Hiimphteve in https://github.com/sidebase/nuxt-auth/pull/739 +* docs: Adjusted Recommended NextAuth Version by @zoey-kaiser in https://github.com/sidebase/nuxt-auth/pull/741 +* fix: fix and improve auto-declaration generation by @phoenix-ru in https://github.com/sidebase/nuxt-auth/pull/747 +* feat: Add cookie domain config by @pier-lucRVezy in https://github.com/sidebase/nuxt-auth/pull/736 +* fix(types): export interface for module builder type generation by @BobbieGoede in https://github.com/sidebase/nuxt-auth/pull/738 +* enh(#742): optimize internal $fetch calls by @phoenix-ru in https://github.com/sidebase/nuxt-auth/pull/750 +* release: 0.8.0-alpha.1 by @zoey-kaiser in https://github.com/sidebase/nuxt-auth/pull/752 +* fix: opt in to `import.meta.*` properties by @danielroe in https://github.com/sidebase/nuxt-auth/pull/719 +* [PR changes #392] feat: move pointer and sessionDataType to the SessionConfig by @valh1996 in https://github.com/sidebase/nuxt-auth/pull/592 +* feat: Add support for secure attribute of local/refresh provider cookies by @matteioo in https://github.com/sidebase/nuxt-auth/pull/729 +* fix: don't send sign-in options in request payload by @despatates in https://github.com/sidebase/nuxt-auth/pull/755 +* fix: fix type generation being faulty by @phoenix-ru in https://github.com/sidebase/nuxt-auth/pull/756 +* feat: Add support for custom refresh handling by @blumewas in https://github.com/sidebase/nuxt-auth/pull/715 +* release: 0.8.0-alpha.2 by @zoey-kaiser in https://github.com/sidebase/nuxt-auth/pull/757 +* 📝 docs: add session config.md by @blumewas in https://github.com/sidebase/nuxt-auth/pull/758 +* docs: fix broken links and minor rewording by @morehawes in https://github.com/sidebase/nuxt-auth/pull/767 +* enh(#765): refactor `refreshHandler` and session refreshing; fix refresh provider refreshing by @phoenix-ru in https://github.com/sidebase/nuxt-auth/pull/766 +* fix: await sendRedirect in auth handler by @DavidDeSloovere in https://github.com/sidebase/nuxt-auth/pull/769 +* fix: Added getCurrentInstance check to conditionally register onMounted in useAuthState. by @cip8 in https://github.com/sidebase/nuxt-auth/pull/771 +* release: 0.8.0-alpha.3 by @zoey-kaiser in https://github.com/sidebase/nuxt-auth/pull/778 +* fix: properly disable `getSession` endpoint for local and refresh by @Armillus in https://github.com/sidebase/nuxt-auth/pull/768 +* fix: addDefaultCallback can be set with refresh and local providers by @nojiritakeshi in https://github.com/sidebase/nuxt-auth/pull/710 +* release: 0.8.0-rc.1 by @zoey-kaiser in https://github.com/sidebase/nuxt-auth/pull/779 +* Revert "fix: properly disable `getSession` endpoint for local and refresh" by @zoey-kaiser in https://github.com/sidebase/nuxt-auth/pull/788 +* release: 0.8.0 by @zoey-kaiser in https://github.com/sidebase/nuxt-auth/pull/789 + +**Full Changelog**: https://github.com/sidebase/nuxt-auth/compare/0.7.2...0.8.0 diff --git a/docs/upgrade/version-0.9.0.md b/docs/upgrade/version-0.9.0.md new file mode 100644 index 00000000..29b36419 --- /dev/null +++ b/docs/upgrade/version-0.9.0.md @@ -0,0 +1,93 @@ +# Upgrade to 0.9.0 + +> This release contains breaking changes for the **`refresh` provider**. + +## Installation + +::: code-group + +```bash [npm] +npm i -D @sidebase/nuxt-auth@^0.9.0 +``` + +```bash [pnpm] +pnpm i -D @sidebase/nuxt-auth^0.9.0 +``` + +```bash [yarn] +yarn add --dev @sidebase/nuxt-auth^0.9.0 +``` + +::: + +## Breaking Changes + +### Unification of `local` and `refresh` provider + +In `0.9.0` we unified the `local` and `refresh` providers into one. When we originally developed NuxtAuth, there was a lot of split logic, that could not be reused. Since then we unified many functions together which now allows us to build the `local` and `refresh` providers from the same base. + +This update will streamline additions to the providers, as changes made will automatically be reflected in both providers, unlike before, where changes needed to be added to both the `local` and `refresh` provider. + +Below you can see what changes need to be made to upgrade to `0.9.0` if you were previusly using the `refresh` provider. If you were using the `local` or `authjs` provider, you don't need to make any adjustments: + +```ts +// nuxt.config.ts +export default defineNuxtConfig({ + modules: ['@sidebase/nuxt-auth'], + auth: { + provider: { + type: 'refresh', // [!code --] + type: 'local', // [!code ++] + endpoints: { + getSession: { path: '/session', method: 'get' }, + refresh: { path: '/refresh', method: 'post' } // [!code --] + }, + refreshOnlyToken: true, // [!code --] + refreshToken: { // [!code --] + signInResponseRefreshTokenPointer: '/refresh-token', // [!code --] + refreshRequestTokenPointer: 'Bearer', // [!code --] + cookieName: 'auth.token', // [!code --] + maxAgeInSeconds: 1800, // [!code --] + cookieDomain: 'sidebase.io', // [!code --] + secureCookieAttribute: false, // [!code --] + httpOnlyCookieAttribute: false, // [!code --] + }, // [!code --] + refresh: { // [!code ++] + isEnabled: true, // [!code ++] + endpoint: { path: '/refresh', method: 'POST' }, // [!code ++] + refreshOnlyToken: true, // [!code ++] + token: { // [!code ++] + signInResponseRefreshTokenPointer: '/refresh-token', // [!code ++] + refreshRequestTokenPointer: 'Bearer', // [!code ++] + cookieName: 'auth.token', // [!code ++] + maxAgeInSeconds: 1800, // [!code ++] + sameSiteAttribute: 'lax', // [!code ++] + secureCookieAttribute: false, // [!code ++] + cookieDomain: 'sidebase.io', // [!code ++] + httpOnlyCookieAttribute: false, // [!code ++] + } // [!code ++] + }, + }, + } +}) +``` + +The configuration values that were unquie to the `refresh` provider have now been moved into one `refresh` configuration inside the `local` provider. `refreshToken` was also renamed to `token`, as it now resides inside a `refresh` configuration point. + +### Node version requirement + +Starting from `v0.9.0`, we now require a node version of at least 20. Node version 16 has now left maintaince mode and support for version 18 is ending in 2025. Read more [here](https://nodejs.org/en/about/previous-releases). + +## Changelog + +* fix(#834): Do not refresh on window focus for unprotected pages by @YoshimiShima in https://github.com/sidebase/nuxt-auth/pull/858 +* chore: add metadata fields to package.json by @MuhammadM1998 in https://github.com/sidebase/nuxt-auth/pull/864 +* fix(#860): make node version requirement less strict by @phoenix-ru in https://github.com/sidebase/nuxt-auth/pull/865 +* docs: Add recipes section and copy old recipes by @zoey-kaiser in https://github.com/sidebase/nuxt-auth/pull/868 +* chore: add plausible site analytics by @zoey-kaiser in https://github.com/sidebase/nuxt-auth/pull/869 +* feat(#673, #523, #848): back-port authjs migration by @phoenix-ru in https://github.com/sidebase/nuxt-auth/pull/849 +* feat(#821): Unify `local` and `refresh` providers into one by @zoey-kaiser in https://github.com/sidebase/nuxt-auth/pull/822 +* chore: updated ESLint and general housekeeping by @zoey-kaiser in https://github.com/sidebase/nuxt-auth/pull/853 +* chore: update docs for `0.9.0` by @zoey-kaiser in https://github.com/sidebase/nuxt-auth/pull/873 + +**Full Changelog**: https://github.com/sidebase/nuxt-auth/compare/0.8.2...0.9.0 diff --git a/package.json b/package.json index 9b6a9ad5..aa57cbaa 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,11 @@ { "name": "@sidebase/nuxt-auth", - "version": "0.8.2", + "version": "0.9.1", "license": "MIT", "type": "module", "description": "Authentication built for Nuxt 3! Easily add authentication via OAuth providers, credentials or Email Magic URLs!", "homepage": "https://auth.sidebase.io", - "repository": { - "type": "git", - "url": "https://github.com/sidebase/nuxt-auth" - }, + "repository": "github:sidebase/nuxt-auth", "engines": { "pnpm": ">=9.4.0", "node": ">=20" @@ -28,7 +25,7 @@ "scripts": { "prepack": "nuxt-module-build build", "build": "nuxi build", - "lint": "oxlint --deny-warnings -D correctness -D suspicious -D perf && eslint . --max-warnings=0", + "lint": "oxlint --deny-warnings -D correctness -D suspicious -D perf -D no-unused-vars && eslint . --max-warnings=0", "lint:fix": "eslint . --max-warnings=0 --fix", "clean": "rm -rf playground-authjs/.nuxt playground-local/.nuxt playground-refresh/.nuxt dist .nuxt", "typecheck": "nuxi prepare playground-local && tsc --noEmit", @@ -67,4 +64,4 @@ "vue-tsc": "^2.0.29" }, "packageManager": "pnpm@9.6.0+sha512.38dc6fba8dba35b39340b9700112c2fe1e12f10b17134715a4aa98ccf7bb035e76fd981cf0bb384dfa98f8d6af5481c2bef2f4266a24bfa20c34eb7147ce0b5e" -} \ No newline at end of file +} diff --git a/playground-local/app.vue b/playground-local/app.vue index c80b0ca0..6ccd2788 100644 --- a/playground-local/app.vue +++ b/playground-local/app.vue @@ -2,7 +2,7 @@ import { ref } from 'vue' import { useAuth } from '#imports' -const { signIn, token, data, status, lastRefreshedAt, signOut, getSession } = useAuth() +const { signIn, token, refreshToken, data, status, lastRefreshedAt, signOut, getSession } = useAuth() const username = ref('') const password = ref('') @@ -14,6 +14,7 @@ const password = ref('')
Data: {{ data || 'no session data present, are you logged in?' }}
Last refreshed at: {{ lastRefreshedAt || 'no refresh happened' }}
JWT token: {{ token || 'no token present, are you logged in?' }}
+
Refresh token: {{ refreshToken || 'N/A' }}
diff --git a/src/runtime/composables/local/useAuth.ts b/src/runtime/composables/local/useAuth.ts index 6d9b8a9f..1368fe0d 100644 --- a/src/runtime/composables/local/useAuth.ts +++ b/src/runtime/composables/local/useAuth.ts @@ -14,7 +14,7 @@ import { navigateTo, nextTick, useNuxtApp, useRuntimeConfig } from '#imports' type Credentials = { username?: string, email?: string, password?: string } & Record -const signIn: SignInFunc = async (credentials, signInOptions, signInParams) => { +const signIn: SignInFunc = async (credentials, signInOptions, signInParams, signInHeaders) => { const nuxt = useNuxtApp() const runtimeConfig = await callWithNuxt(nuxt, useRuntimeConfig) @@ -23,7 +23,8 @@ const signIn: SignInFunc = async (credentials, signInOptions, const response = await _fetch>(nuxt, path, { method, body: credentials, - params: signInParams ?? {} + params: signInParams ?? {}, + headers: signInHeaders ?? {} }) const { rawToken, rawRefreshToken } = useAuthState() diff --git a/src/runtime/composables/local/useAuthState.ts b/src/runtime/composables/local/useAuthState.ts index 32a238ee..67a6f836 100644 --- a/src/runtime/composables/local/useAuthState.ts +++ b/src/runtime/composables/local/useAuthState.ts @@ -91,7 +91,7 @@ export function useAuthState(): UseAuthStateReturn { } } - const refreshToken = computed(() => formatToken(rawRefreshToken.value, config)) + const refreshToken = computed(() => rawRefreshToken.value) return { ...commonAuthState, diff --git a/src/runtime/types.ts b/src/runtime/types.ts index e728ca25..0827b417 100644 --- a/src/runtime/types.ts +++ b/src/runtime/types.ts @@ -590,7 +590,8 @@ export type SignOutFunc = (options?: SignOutOptions) => Promise export type SignInFunc = ( primaryOptions: PrimarySignInOptions, signInOptions?: SecondarySignInOptions, - paramsOptions?: Record + paramsOptions?: Record, + headersOptions?: Record ) => Promise export interface ModuleOptionsNormalized extends ModuleOptions {