diff --git a/playground-local/nuxt.config.ts b/playground-local/nuxt.config.ts index 4f6e5c5e..94a2c967 100644 --- a/playground-local/nuxt.config.ts +++ b/playground-local/nuxt.config.ts @@ -8,7 +8,8 @@ export default defineNuxtConfig({ provider: { type: 'local', endpoints: { - getSession: { path: '/user' } + getSession: { path: '/user' }, + signUp: { path: '/signup', method: 'post' } }, pages: { login: '/' diff --git a/playground-local/pages/index.vue b/playground-local/pages/index.vue index 5b9707ab..a87a48b9 100644 --- a/playground-local/pages/index.vue +++ b/playground-local/pages/index.vue @@ -10,6 +10,10 @@ definePageMeta({ auth: false }) -> manual login, logout, refresh button
+ + -> Click to signup + +
-> globally protected page diff --git a/playground-local/pages/register.vue b/playground-local/pages/register.vue new file mode 100644 index 00000000..f23ac214 --- /dev/null +++ b/playground-local/pages/register.vue @@ -0,0 +1,45 @@ + + + diff --git a/playground-local/server/api/auth/signup.post.ts b/playground-local/server/api/auth/signup.post.ts new file mode 100644 index 00000000..849f7d3a --- /dev/null +++ b/playground-local/server/api/auth/signup.post.ts @@ -0,0 +1,40 @@ +import { createError, eventHandler, readBody } from 'h3' +import { z } from 'zod' +import { sign } from 'jsonwebtoken' + +export const SECRET = 'dummy' + +export default eventHandler(async (event) => { + // Define the schema for validating the incoming data + const result = z.object({ + username: z.string(), + password: z.string().min(6) + }).safeParse(await readBody(event)) + + // If validation fails, return an error + if (!result.success) { + throw createError({ + statusCode: 400, + statusMessage: 'Invalid input, please provide a valid email and a password of at least 6 characters.' + }) + } + + const { username } = result.data + + const expiresIn = '1h' // token expiry (1 hour) + const user = { username } // Payload for the token, includes the email + + // Sign the JWT with the user payload and secret + const accessToken = sign(user, SECRET, { expiresIn }) + + // Return a success response with the email and the token + return { + message: 'Signup successful!', + user: { + username + }, + token: { + accessToken + } + } +}) diff --git a/playground-local/tests/local.spec.ts b/playground-local/tests/local.spec.ts index 29abeae5..33cd9b37 100644 --- a/playground-local/tests/local.spec.ts +++ b/playground-local/tests/local.spec.ts @@ -59,4 +59,30 @@ describe('local Provider', async () => { await signoutButton.click() await playwrightExpect(status).toHaveText(STATUS_UNAUTHENTICATED) }) + + it('should sign up and return signup data when preventLoginFlow: true', async () => { + const page = await createPage('/register') // Navigate to signup page + + const [ + usernameInput, + passwordInput, + submitButton, + ] = await Promise.all([ + page.getByTestId('username'), + page.getByTestId('password'), + page.getByTestId('submit') + ]) + + await usernameInput.fill('newuser') + await passwordInput.fill('hunter2') + + // Click button and wait for API to finish + const responsePromise = page.waitForResponse(/\/api\/auth\/signup/) + await submitButton.click() + const response = await responsePromise + + // Expect the response to return signup data + const responseBody = await response.json() // Parse response + playwrightExpect(responseBody).toBeDefined() // Ensure data is returned + }) }) diff --git a/src/runtime/composables/local/useAuth.ts b/src/runtime/composables/local/useAuth.ts index cd4ff21c..51fb0a8a 100644 --- a/src/runtime/composables/local/useAuth.ts +++ b/src/runtime/composables/local/useAuth.ts @@ -1,5 +1,4 @@ import { type Ref, readonly } from 'vue' - import type { CommonUseAuthReturn, GetSessionOptions, SecondarySignInOptions, SignInFunc, SignOutFunc, SignUpOptions } from '../../types' import { jsonPointerGet, objectFromJsonPointer, useTypedBackendConfig } from '../../helpers' import { _fetch } from '../../utils/fetch' @@ -160,17 +159,19 @@ async function getSession(getSessionOptions?: GetSessionOptions): Promise(credentials: Credentials, signInOptions?: SecondarySignInOptions, signUpOptions?: SignUpOptions): Promise { const nuxt = useNuxtApp() const { path, method } = useTypedBackendConfig(useRuntimeConfig(), 'local').endpoints.signUp - await _fetch(nuxt, path, { + + // Holds result from fetch to be returned if signUpOptions?.preventLoginFlow is true + const result = await _fetch(nuxt, path, { method, body: credentials }) if (signUpOptions?.preventLoginFlow) { - return + return result } return signIn(credentials, signInOptions)