Skip to content

Commit 4b38b60

Browse files
committed
chore: fix lints
1 parent 51ba295 commit 4b38b60

10 files changed

Lines changed: 116 additions & 103 deletions

File tree

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ npx nuxi@latest module add sidebase-auth
3939
<details>
4040
<summary>Or install manually</summary>
4141

42-
#### 1. Install the package as a dev dependency
42+
### 1. Install the package as a dev dependency
4343

4444
```sh
4545
npm i -D @sidebase/nuxt-auth
@@ -49,7 +49,7 @@ npx nuxi@latest module add sidebase-auth
4949
yarn add --dev @sidebase/nuxt-auth
5050
```
5151

52-
#### 2. Add the modules to your `nuxt.config.ts`
52+
### 2. Add the modules to your `nuxt.config.ts`
5353

5454
```ts
5555
export default defineNuxtConfig({
@@ -174,5 +174,5 @@ Thank you to everyone who has contributed to this project by writing issues or o
174174
`@sidebase/nuxt-auth` is supported by all of our amazing contributors and the [Nuxt 3+ team](https://nuxters.nuxt.com/)!
175175

176176
<a href="https://github.com/sidebase/nuxt-auth/graphs/contributors">
177-
<img src="https://contrib.rocks/image?repo=sidebase/nuxt-auth" />
177+
<img src="https://contrib.rocks/image?repo=sidebase/nuxt-auth" alt="Contributors" />
178178
</a>

docs/guide/getting-started/choose-provider.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ In `v0.9.0` the `refresh` provider was integrated into the `local` provider. Rea
1515

1616
If you are still unsure, below are some tables to help you pick:
1717

18-
### Authentication Methods
18+
## Authentication Methods
1919

2020
| | authjs provider | local provider
2121
|----------------------------------------------------------- |-------------------------------------: |---------------:
@@ -24,7 +24,7 @@ If you are still unsure, below are some tables to help you pick:
2424
| Credentials / Username + Password flow | 🚧 (if possible: use `local` instead) | ✅
2525
| Refresh tokens | ✅ | ✅
2626

27-
### Features
27+
## Features
2828

2929
| | authjs provider | local provider
3030
|----------------------------------------------------------- |-------------------------------------: |------:

docs/guide/getting-started/introduction.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ NextAuth versions under `4.22` are impacted by vulnerability [GHSA-v64w-49xw-qq8
4646

4747
::: details Further details
4848
---
49-
#### Description of the vulnerability
49+
### Description of the vulnerability
5050
The vulnerability [GHSA-v64w-49xw-qq89](https://github.com/advisories/GHSA-v64w-49xw-qq89) only affects applications that rely on the default [Middleware authorization](https://next-auth.js.org/configuration/nextjs#middleware) provided by NextAuth.
5151

5252
The vulnerability allows attackers to create/mock a user, by accessing the JWT from an interrupted OAuth sign-in flow. They can then manually override the session cookie and simulate a login. However, doing this does **not** give access to the users data or permissions, but can allow attackers to view the layouts of protected pages.
5353

54-
#### Why does it not effect NuxtAuth?
54+
### Why does it not affect NuxtAuth?
5555
As the affected middleware is written for Next.js, we wrote our own [custom middleware](https://github.com/sidebase/nuxt-auth/blob/main/src/runtime/middleware/auth.ts) for NuxtAuth that is not affected by the vulnerability.
5656
:::

playground-authjs/pages/custom-signin.vue

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,13 @@ const password = ref('')
99
1010
const { signIn } = useAuth()
1111
12-
async function mySignInHandler({ username, password, callbackUrl }: { username: string, password: string, callbackUrl: string }) {
13-
const { error, url } = await signIn('credentials', { username, password, callbackUrl, redirect: false })
12+
async function mySignInHandler(callbackUrl: string) {
13+
const { error, url } = await signIn('credentials', {
14+
username: username.value,
15+
password: password.value,
16+
callbackUrl,
17+
redirect: false
18+
})
1419
1520
if (error) {
1621
// Do your custom error handling here
@@ -39,7 +44,7 @@ async function mySignInHandler({ username, password, callbackUrl }: { username:
3944
Sign in with username and password
4045
</button>
4146
<br>
42-
<button @click="mySignInHandler({ username, password, callbackUrl: '/protected/globally' })">
47+
<button @click="mySignInHandler('/protected/globally')">
4348
Sign in with username and password using a custom sign in handler
4449
</button>
4550
</div>

playground-local/server/utils/session.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ interface TokensByUser {
3333
* Tokens storage.
3434
* You will need to implement your own, connect with DB/etc.
3535
*/
36-
const tokensByUser: Map<string, TokensByUser> = new Map()
36+
const tokensByUserMap: Map<string, TokensByUser> = new Map()
3737

3838
/**
3939
* We use a fixed password for demo purposes.
@@ -72,13 +72,13 @@ export async function createUserTokens(user: User): Promise<UserTokens> {
7272
const refreshToken = await createSignedJwt(tokenData, /* 1 day */ 60 * 60 * 24)
7373

7474
// Naive implementation - please implement properly yourself!
75-
const userTokens: TokensByUser = tokensByUser.get(user.username) ?? {
75+
const userTokens: TokensByUser = tokensByUserMap.get(user.username) ?? {
7676
access: new Map(),
7777
refresh: new Map()
7878
}
7979
userTokens.access.set(accessToken, refreshToken)
8080
userTokens.refresh.set(refreshToken, accessToken)
81-
tokensByUser.set(user.username, userTokens)
81+
tokensByUserMap.set(user.username, userTokens)
8282

8383
return {
8484
accessToken,
@@ -99,7 +99,7 @@ export async function decodeToken(token: string): Promise<JWTPayload> {
9999
* Your implementation will likely never need this and will rely on User ID and DB.
100100
*/
101101
export function getTokensByUser(username: string): TokensByUser | undefined {
102-
return tokensByUser.get(username)
102+
return tokensByUserMap.get(username)
103103
}
104104

105105
type CheckUserTokensResult = { valid: true, knownAccessToken: string } | { valid: false, knownAccessToken: undefined }

src/module.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ const defaultsByBackend: {
102102
const PACKAGE_NAME = 'sidebase-auth'
103103
const MIDDLEWARE_NAME = PACKAGE_NAME
104104

105+
const TS_ENDS_RE = /\.ts$/
106+
105107
export default defineNuxtModule<ModuleOptions>({
106108
meta: {
107109
name: PACKAGE_NAME,
@@ -224,7 +226,7 @@ export default defineNuxtModule<ModuleOptions>({
224226
filename: './refreshHandler.ts',
225227
async getContents() {
226228
if (options.sessionRefresh.handler) {
227-
const path = (await resolvePath(options.sessionRefresh.handler)).replace(/\.ts$/, '')
229+
const path = (await resolvePath(options.sessionRefresh.handler)).replace(TS_ENDS_RE, '')
228230
return `export { default as _refreshHandler } from '${path}'`
229231
}
230232

src/runtime/composables/authjs/useAuth.ts

Lines changed: 76 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { _fetch } from '../../utils/fetch'
88
import { isNonEmptyObject } from '../../utils/checkSessionResult'
99
import type { CommonUseAuthReturn, GetSessionOptions, SecondarySignInOptions, SignOutOptions } from '../../types'
1010
import { useTypedBackendConfig } from '../../helpers'
11-
import { getRequestURLWN } from '../common/getRequestURL'
11+
import { getRequestURL } from '../common/getRequestURL'
1212
import { determineCallbackUrl } from '../../utils/callbackUrl'
1313
import type { SessionData } from './useAuthState'
1414
import { navigateToAuthPageWN } from './utils/navigateToAuthPage'
@@ -147,7 +147,7 @@ export function useAuth(): UseAuthReturn {
147147

148148
const action: 'callback' | 'signin' = isCredentials ? 'callback' : 'signin'
149149

150-
const csrfToken = await getCsrfTokenWithNuxt(nuxt)
150+
const csrfToken = await getCsrfToken()
151151

152152
const headers: { 'Content-Type': string, 'cookie'?: string, 'host'?: string } = {
153153
'Content-Type': 'application/x-www-form-urlencoded',
@@ -175,10 +175,10 @@ export function useAuth(): UseAuthReturn {
175175
)
176176
.catch<Record<string, any>>((error: { data: any }) => error.data)
177177

178-
const data = await callWithNuxt(nuxt, fetchSignIn)
178+
const signInData = await callWithNuxt(nuxt, fetchSignIn)
179179

180180
if (redirect || !isSupportingReturn) {
181-
const href = data.url ?? callbackUrl
181+
const href = signInData.url ?? callbackUrl
182182
const navigationResult = await navigateToAuthPageWN(nuxt, href)
183183

184184
// We use `http://_` as a base to allow relative URLs in `callbackUrl`. We only need the `error` query param
@@ -194,14 +194,14 @@ export function useAuth(): UseAuthReturn {
194194
}
195195

196196
// At this point the request succeeded (i.e., it went through)
197-
const error = new URL(data.url).searchParams.get('error')
198-
await getSessionWithNuxt(nuxt)
197+
const error = new URL(signInData.url).searchParams.get('error')
198+
await getSession()
199199

200200
return {
201201
error,
202202
status: 200,
203203
ok: true,
204-
url: error ? null : data.url,
204+
url: error ? null : signInData.url,
205205
navigationResult: undefined,
206206
}
207207
}
@@ -226,73 +226,72 @@ export function useAuth(): UseAuthReturn {
226226
* @param getSessionOptions - Options for getting the session, e.g., set `required: true` to enforce that a session _must_ exist, the user will be directed to a login page otherwise.
227227
*/
228228
async function getSession(getSessionOptions?: GetSessionOptions): Promise<SessionData | null> {
229-
const callbackUrlFallback = await getRequestURLWN(nuxt)
230-
const { required, callbackUrl, onUnauthenticated } = defu(getSessionOptions || {}, {
231-
required: false,
232-
callbackUrl: undefined,
233-
onUnauthenticated: () => signIn(undefined, {
234-
callbackUrl: getSessionOptions?.callbackUrl || callbackUrlFallback
229+
return callWithNuxt(nuxt, async () => {
230+
const callbackUrlFallback = getRequestURL()
231+
const { required, callbackUrl, onUnauthenticated } = defu(getSessionOptions || {}, {
232+
required: false,
233+
callbackUrl: undefined,
234+
onUnauthenticated: () => signIn(undefined, {
235+
callbackUrl: getSessionOptions?.callbackUrl || callbackUrlFallback
236+
})
235237
})
236-
})
237-
238-
function onError() {
239-
loading.value = false
240-
}
241238

242-
const headers = await getRequestHeaders(nuxt)
243-
244-
return _fetch<SessionData>(nuxt, '/session', {
245-
onResponse: ({ response }) => {
246-
const sessionData = response._data
239+
function onError() {
240+
loading.value = false
241+
}
247242

248-
// Add any new cookie to the server-side event for it to be present on the app-side after
249-
// initial load, see sidebase/nuxt-auth/issues/200 for more information.
250-
if (import.meta.server) {
251-
const setCookieValues = response.headers.getSetCookie ? response.headers.getSetCookie() : [response.headers.get('set-cookie')]
252-
if (setCookieValues && nuxt.ssrContext) {
253-
for (const value of setCookieValues) {
254-
if (!value) {
255-
continue
243+
const headers = await getRequestHeaders(nuxt)
244+
245+
return _fetch<SessionData>(nuxt, '/session', {
246+
onResponse: ({ response }) => {
247+
const sessionData = response._data
248+
249+
// Add any new cookie to the server-side event for it to be present on the app-side after
250+
// initial load, see sidebase/nuxt-auth/issues/200 for more information.
251+
if (import.meta.server) {
252+
const setCookieValues = response.headers.getSetCookie ? response.headers.getSetCookie() : [response.headers.get('set-cookie')]
253+
if (setCookieValues && nuxt.ssrContext) {
254+
for (const value of setCookieValues) {
255+
if (!value) {
256+
continue
257+
}
258+
appendHeader(nuxt.ssrContext.event, 'set-cookie', value)
256259
}
257-
appendHeader(nuxt.ssrContext.event, 'set-cookie', value)
258260
}
259261
}
260-
}
261262

262-
data.value = isNonEmptyObject(sessionData) ? sessionData : null
263-
loading.value = false
263+
data.value = isNonEmptyObject(sessionData) ? sessionData : null
264+
loading.value = false
264265

265-
if (required && status.value === 'unauthenticated') {
266-
return onUnauthenticated()
267-
}
266+
if (required && status.value === 'unauthenticated') {
267+
return onUnauthenticated()
268+
}
268269

269-
return sessionData
270-
},
271-
onRequest: ({ options }) => {
272-
lastRefreshedAt.value = new Date()
270+
return sessionData
271+
},
272+
onRequest: ({ options }) => {
273+
lastRefreshedAt.value = new Date()
273274

274-
options.params = {
275-
...options.params,
276-
callbackUrl: callbackUrl || callbackUrlFallback
277-
}
278-
},
279-
onRequestError: onError,
280-
onResponseError: onError,
281-
headers
282-
}, /* proxyCookies = */ true)
283-
}
284-
function getSessionWithNuxt(nuxt: NuxtApp) {
285-
return callWithNuxt(nuxt, getSession)
275+
options.params = {
276+
...options.params,
277+
callbackUrl: callbackUrl || callbackUrlFallback
278+
}
279+
},
280+
onRequestError: onError,
281+
onResponseError: onError,
282+
headers
283+
}, /* proxyCookies = */ true)
284+
})
286285
}
287286

288287
/**
289288
* Sign out the current user.
290289
*
291-
* @param options - Options for sign out, e.g., to `redirect` the user to a specific page after sign out has completed
290+
* @param signOutOptions - Options for sign out, e.g., to `redirect` the user to a specific page after sign out has completed
292291
*/
293-
async function signOut(options?: SignOutOptions) {
294-
const { callbackUrl: userCallbackUrl, redirect = true } = options ?? {}
295-
const csrfToken = await getCsrfTokenWithNuxt(nuxt)
292+
async function signOut(signOutOptions?: SignOutOptions) {
293+
const { callbackUrl: userCallbackUrl, redirect = true } = signOutOptions ?? {}
294+
const csrfToken = await getCsrfToken()
296295

297296
// Determine the correct callback URL
298297
const callbackUrl = await determineCallbackUrl(
@@ -325,35 +324,20 @@ export function useAuth(): UseAuthReturn {
325324
return navigateToAuthPageWN(nuxt, url)
326325
}
327326

328-
await getSessionWithNuxt(nuxt)
327+
await getSession()
329328
return signoutData
330329
}
331330

332-
/**
333-
* Utilities to make nested async composable calls play nicely with nuxt.
334-
*
335-
* Calling nested async composable can lead to "nuxt instance unavailable" errors. See more details here: https://github.com/nuxt/framework/issues/5740#issuecomment-1229197529. To resolve this we can manually ensure that the nuxt-context is set. This module contains `callWithNuxt` helpers for some of the methods that are frequently called in nested `useAuth` composable calls.
336-
*/
337-
async function getRequestHeaders(nuxt: NuxtApp, includeCookie = true): Promise<{ cookie?: string, host?: string }> {
338-
// `useRequestHeaders` is sync, so we narrow it to the awaited return type here
339-
const headers = await callWithNuxt(nuxt, () => useRequestHeaders(['cookie', 'host']))
340-
if (includeCookie && headers.cookie) {
341-
return headers
342-
}
343-
return { host: headers.host }
344-
}
345-
346331
/**
347332
* Get the current Cross-Site Request Forgery token.
348333
*
349334
* You can use this to pass along for certain requests, most of the time you will not need it.
350335
*/
351336
async function getCsrfToken() {
352-
const headers = await getRequestHeaders(nuxt)
353-
return _fetch<{ csrfToken: string }>(nuxt, '/csrf', { headers }).then(response => response.csrfToken)
354-
}
355-
function getCsrfTokenWithNuxt(nuxt: NuxtApp) {
356-
return callWithNuxt(nuxt, getCsrfToken)
337+
return callWithNuxt(nuxt, async () => {
338+
const headers = await getRequestHeaders(nuxt)
339+
return _fetch<{ csrfToken: string }>(nuxt, '/csrf', { headers }).then(response => response.csrfToken)
340+
})
357341
}
358342

359343
return {
@@ -369,3 +353,17 @@ export function useAuth(): UseAuthReturn {
369353
}
370354
}
371355
export default useAuth
356+
357+
/**
358+
* Utilities to make nested async composable calls play nicely with nuxt.
359+
*
360+
* Calling nested async composable can lead to "nuxt instance unavailable" errors. See more details here: https://github.com/nuxt/framework/issues/5740#issuecomment-1229197529. To resolve this we can manually ensure that the nuxt-context is set. This module contains `callWithNuxt` helpers for some of the methods that are frequently called in nested `useAuth` composable calls.
361+
*/
362+
async function getRequestHeaders(nuxt: NuxtApp, includeCookie = true): Promise<{ cookie?: string, host?: string }> {
363+
// `useRequestHeaders` is sync, so we narrow it to the awaited return type here
364+
const headers = await callWithNuxt(nuxt, () => useRequestHeaders(['cookie', 'host']))
365+
if (includeCookie && headers.cookie) {
366+
return headers
367+
}
368+
return { host: headers.host }
369+
}

src/runtime/helpers.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ import type { useRuntimeConfig } from '#imports'
55

66
export const isProduction = process.env.NODE_ENV === 'production'
77

8+
const DIGIT_OR_DASH_RE = /^\d+|-$/
9+
const SLASH_RE = /\//
10+
const TILDE_1_RE = /~1/g
11+
const TILDE_0_RE = /~0/g
12+
813
// We use `DeepRequired` here because options are actually enriched using `defu`
914
// but due to a build error we can't use `DeepRequired` inside runtime config definition.
1015
type RuntimeConfig = ReturnType<typeof useRuntimeConfig>
@@ -90,7 +95,7 @@ export function jsonPointerSet(
9095
nextTok = refTokens[i + 1]
9196

9297
if (!(tok in obj)) {
93-
if (nextTok.match(/^(\d+|-)$/)) {
98+
if (DIGIT_OR_DASH_RE.test(nextTok)) {
9499
obj[tok] = []
95100
}
96101
else {
@@ -129,5 +134,5 @@ function jsonPointerParse(pointer: string): string[] {
129134
if (pointer.charAt(0) !== '/') {
130135
throw new Error(`Invalid JSON pointer: ${pointer}`)
131136
}
132-
return pointer.substring(1).split(/\//).map(s => s.replace(/~1/g, '/').replace(/~0/g, '~'))
137+
return pointer.substring(1).split(SLASH_RE).map(s => s.replace(TILDE_1_RE, '/').replace(TILDE_0_RE, '~'))
133138
}

0 commit comments

Comments
 (0)