diff --git a/docs/content/2.configuration/2.nuxt-config.md b/docs/content/2.configuration/2.nuxt-config.md index e26b4a35..053be117 100644 --- a/docs/content/2.configuration/2.nuxt-config.md +++ b/docs/content/2.configuration/2.nuxt-config.md @@ -247,14 +247,31 @@ type ProviderLocal = { */ cookieDomain?: string; }, - /** - * Define an interface for the session data object that `nuxt-auth` expects to receive from the `getSession` endpoint. - * - * @default { id: 'string | number' } - * @example { id: 'string', name: 'string', email: 'string' } - * @advanced_array_example { id: 'string', email: 'string', name: 'string', role: 'admin | guest | account', subscriptions: "{ id: number, status: 'ACTIVE' | 'INACTIVE' }[]" } + /* + * Settings for the session-data that `nuxt-auth` receives from the `getSession` endpoint. */ - sessionDataType?: SessionDataObject, + session?: { + /** + * Define an interface for the session data object that `nuxt-auth` expects to receive from the `getSession` endpoint. + * + * @default { id: 'string | number' } + * @example { id: 'string', name: 'string', email: 'string' } + * @advanced_array_example { id: 'string', email: 'string', name: 'string', role: 'admin | guest | account', subscriptions: "{ id: number, status: 'ACTIVE' | 'INACTIVE' }[]" } + */ + dataType?: SessionDataObject; + /** + * How to extract the session-data from the session response. + * + * E.g., setting this to `/data/user` and returning an object like `{ data: { user: { id:number, name: string } }, status: 'ok' }` from the `getSession` endpoint will + * storing the 'User' object typed as the type created via the 'dataType' prop. + * + * This follows the JSON Pointer standard, see it's RFC6901 here: https://www.rfc-editor.org/rfc/rfc6901 + * + * @default / Access the root of the session response object + * @example /data/user Access the `data/user` property of the session response object + */ + dataResponsePointer?: string; + } } ``` @@ -406,7 +423,7 @@ type ProviderRefresh = { * @default '/refreshToken' Access the `refreshToken` property of the sign-in response object * @example / Access the root of the sign-in response object, useful when your endpoint returns a plain, non-object string as the refreshToken */ - signInResponseRefreshTokenPointer?: string + signInResponseRefreshTokenPointer?: string, /** * How to do a fetch for the refresh token. * @@ -445,14 +462,31 @@ type ProviderRefresh = { */ cookieDomain?: string; }, - /** - * Define an interface for the session data object that `nuxt-auth` expects to receive from the `getSession` endpoint. - * - * @default { id: 'string | number' } - * @example { id: 'string', name: 'string', email: 'string' } - * @advanced_array_example { id: 'string', email: 'string', name: 'string', role: 'admin | guest | account', subscriptions: "{ id: number, status: 'ACTIVE' | 'INACTIVE' }[]" } + /* + * Settings for the session-data that `nuxt-auth` receives from the `getSession` endpoint. */ - sessionDataType?: SessionDataObject, + session?: { + /** + * Define an interface for the session data object that `nuxt-auth` expects to receive from the `getSession` endpoint. + * + * @default { id: 'string | number' } + * @example { id: 'string', name: 'string', email: 'string' } + * @advanced_array_example { id: 'string', email: 'string', name: 'string', role: 'admin | guest | account', subscriptions: "{ id: number, status: 'ACTIVE' | 'INACTIVE' }[]" } + */ + dataType?: SessionDataObject; + /** + * How to extract the session-data from the session response. + * + * E.g., setting this to `/data/user` and returning an object like `{ data: { user: { id:number, name: string } }, status: 'ok' }` from the `getSession` endpoint will + * storing the 'User' object typed as the type created via the 'dataType' prop. + * + * This follows the JSON Pointer standard, see it's RFC6901 here: https://www.rfc-editor.org/rfc/rfc6901 + * + * @default / Access the root of the session response object + * @example /data/user Access the `data/user` property of the session response object + */ + dataResponsePointer?: string; + } } ``` ```ts [SessionConfig] @@ -471,7 +505,7 @@ type SessionConfig = { * @default false * */ - enableRefreshPeriodically: number | boolean + enableRefreshPeriodically: number | boolean, /** * Whether to refresh the session every time the browser window is refocused. * diff --git a/docs/content/3.application-side/2.session-access-and-management.md b/docs/content/3.application-side/2.session-access-and-management.md index f76ddcf9..aba38dc4 100644 --- a/docs/content/3.application-side/2.session-access-and-management.md +++ b/docs/content/3.application-side/2.session-access-and-management.md @@ -186,7 +186,7 @@ inferface SessionData { id: string | number } -// Option B: You configured `auth.provider.sessionDataType` to something like ` { id: 'string', email: 'string', name: 'string', role: 'admin | guest | account' }` +// Option B: You configured `auth.provider.session.dataType` to something like ` { id: 'string', email: 'string', name: 'string', role: 'admin | guest | account' }` inferface SessionData { id: string email: string @@ -196,7 +196,7 @@ inferface SessionData { ``` :: -### About `auth.provider.sessionDataType` +### About `auth.provider.session.dataType` This is a configuration option available to dynamically type the `SessionData` that the `local` provider will return when accessing `data.value`. Read more about this in the [nuxt.config.ts configuration documentation](/nuxt-auth/v0.6/configuration/nuxt-config) of the `local` provider. diff --git a/playground-local/nuxt.config.ts b/playground-local/nuxt.config.ts index 63d7ccce..25f2cd4d 100644 --- a/playground-local/nuxt.config.ts +++ b/playground-local/nuxt.config.ts @@ -15,12 +15,14 @@ export default defineNuxtConfig({ token: { signInResponseTokenPointer: '/token/accessToken' }, - sessionDataType: { id: 'string', email: 'string', name: 'string', role: "'admin' | 'guest' | 'account'", subscriptions: "{ id: number, status: 'ACTIVE' | 'INACTIVE' }[]" } + session: { + dataType: { id: 'string', email: 'string', name: 'string', role: "'admin' | 'guest' | 'account'", subscriptions: "{ id: number, status: 'ACTIVE' | 'INACTIVE' }[]" }, + dataResponsePointer: '/' + } }, session: { // Whether to refresh the session every time the browser window is refocused. enableRefreshOnWindowFocus: true, - // Whether to refresh the session every `X` milliseconds. Set this to `false` to turn it off. The session will only be refreshed if a session already exists. enableRefreshPeriodically: 5000 }, diff --git a/src/module.ts b/src/module.ts index e3f20ada..1dae5ed8 100644 --- a/src/module.ts +++ b/src/module.ts @@ -60,7 +60,10 @@ const defaultsByBackend: { sameSiteAttribute: 'lax', cookieDomain: '' }, - sessionDataType: { id: 'string | number' } + session: { + dataType: { id: 'string | number' }, + dataResponsePointer: '/' + } }, refresh: { @@ -92,7 +95,10 @@ const defaultsByBackend: { maxAgeInSeconds: 60 * 60 * 24 * 7, // 7 days cookieDomain: '' }, - sessionDataType: { id: 'string | number' } + session: { + dataType: { id: 'string | number' }, + dataResponsePointer: '/' + } }, authjs: { @@ -201,7 +207,7 @@ export default defineNuxtModule({ ...(options.provider.type === 'local' ? [genInterface( 'SessionData', - (options.provider as any).sessionDataType + (options.provider as any).session.dataType )] : [] ), diff --git a/src/runtime/composables/local/useAuth.ts b/src/runtime/composables/local/useAuth.ts index 73cf5898..11d31c8b 100644 --- a/src/runtime/composables/local/useAuth.ts +++ b/src/runtime/composables/local/useAuth.ts @@ -90,8 +90,14 @@ const getSession: GetSessionFunc = async (getSessionO loading.value = true try { - data.value = await _fetch(nuxt, path, { method, headers }) - } catch { + const result = await _fetch(nuxt, path, { method, headers }) + const { dataResponsePointer: sessionDataResponsePointer } = config.session + data.value = jsonPointerGet(result, sessionDataResponsePointer) + } catch (err) { + if (!data.value && err instanceof Error) { + console.error(`Session: unable to extract session, ${err.message}`) + } + // Clear all data: Request failed so we must not be authenticated data.value = null rawToken.value = null diff --git a/src/runtime/helpers.ts b/src/runtime/helpers.ts index 125c39bd..5ef69bcc 100644 --- a/src/runtime/helpers.ts +++ b/src/runtime/helpers.ts @@ -49,10 +49,10 @@ export const useTypedBackendConfig = ( * @param obj * @param pointer */ -export function jsonPointerGet ( +export function jsonPointerGet > ( obj: Record, pointer: string -): string | Record { +): TResult { const refTokens = Array.isArray(pointer) ? pointer : jsonPointerParse(pointer) for (let i = 0; i < refTokens.length; ++i) { @@ -62,7 +62,7 @@ export function jsonPointerGet ( } obj = obj[tok] } - return obj + return obj as TResult } /** @@ -130,7 +130,7 @@ export function objectFromJsonPointer (pointer: string | string[], value: any): * Adapted from https://github.com/manuelstofer/json-pointer/blob/931b0f9c7178ca09778087b4b0ac7e4f505620c2/index.js#L217-L221 */ function jsonPointerParse (pointer: string): string[] { - if (pointer === '') { + if (pointer === '' || pointer === '/') { return [] } if (pointer.charAt(0) !== '/') { diff --git a/src/runtime/plugins/refresh-token.server.ts b/src/runtime/plugins/refresh-token.server.ts index 4e04f139..1381b446 100644 --- a/src/runtime/plugins/refresh-token.server.ts +++ b/src/runtime/plugins/refresh-token.server.ts @@ -47,7 +47,7 @@ export default defineNuxtPlugin({ return } - // check if refereshTokenOnly + // check if refreshTokenOnly if (!configToken.refreshOnlyToken) { const extractedRefreshToken = jsonPointerGet( response, diff --git a/src/runtime/types.ts b/src/runtime/types.ts index 01f2160c..f18d187c 100644 --- a/src/runtime/types.ts +++ b/src/runtime/types.ts @@ -176,13 +176,30 @@ export type ProviderLocal = { cookieDomain?: string; }; /** - * Define an interface for the session data object that `nuxt-auth` expects to receive from the `getSession` endpoint. - * - * @default { id: 'string | number' } - * @example { id: 'string', name: 'string', email: 'string' } - * @advanced_array_example { id: 'string', email: 'string', name: 'string', role: "'admin' | 'guest' | 'account", subscriptions: "{ id: number, status: 'ACTIVE' | 'INACTIVE' }[]" } + * Settings for the session-data that `nuxt-auth` receives from the `getSession` endpoint. */ - sessionDataType?: SessionDataObject; + session?: { + /* + * Define an interface for the session data object that `nuxt-auth` expects to receive from the `getSession` endpoint. + * + * @default { id: 'string | number' } + * @example { id: 'string', name: 'string', email: 'string' } + * @advanced_array_example { id: 'string', email: 'string', name: 'string', role: "'admin' | 'guest' | 'account'", subscriptions: "{ id: number, status: 'ACTIVE' | 'INACTIVE' }[]" } + */ + dataType?: SessionDataObject; + /** + * How to extract the session-data from the session response. + * + * E.g., setting this to `/data/user` and returning an object like `{ data: { user: { id:number, name: string } }, status: 'ok' }` from the `getSession` endpoint will + * storing the 'User' object typed as the type created via the 'dataType' prop. + * + * This follows the JSON Pointer standard, see it's RFC6901 here: https://www.rfc-editor.org/rfc/rfc6901 + * + * @default / Access the root of the session response object + * @example /data/user Access the `data/user` property of the session response object + */ + dataResponsePointer?: string; + }; }; /**