Skip to content

Commit

Permalink
v3.1.4 (#100)
Browse files Browse the repository at this point in the history
* v3.1.4

- Account for idToken in SSR scenarios for httpOnly
- Typing updates

* update local refresh

* typing update

* Update package.json
  • Loading branch information
Denoder authored Jan 11, 2024
1 parent 9ad54bd commit ea5d9b8
Show file tree
Hide file tree
Showing 15 changed files with 137 additions and 43 deletions.
6 changes: 3 additions & 3 deletions commands/build.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { NuxtModule } from '@nuxt/schema'
import { existsSync, promises as fsp } from 'node:fs'
import { pathToFileURL } from 'url'
import { resolve } from 'path'
import { pathToFileURL } from 'node:url'
import { resolve } from 'node:path'
import { defineCommand } from 'citty'

export default defineCommand({
Expand Down Expand Up @@ -57,9 +57,9 @@ export default defineCommand({
},
externals: [
'#app',
'#vue-router',
'@refactorjs/ofetch',
'ofetch',
'vue-router',
'@nuxt/schema',
'@nuxt/schema-edge',
'@nuxt/kit',
Expand Down
9 changes: 4 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@nuxt-alt/auth",
"version": "3.1.3",
"version": "3.1.4",
"description": "An alternative module to @nuxtjs/auth",
"homepage": "https://github.com/nuxt-alt/auth",
"author": "Denoder",
Expand Down Expand Up @@ -37,7 +37,7 @@
},
"dependencies": {
"@nuxt-alt/http": "latest",
"@nuxt/kit": "^3.8.2",
"@nuxt/kit": "^3.9.1",
"@refactorjs/serialize": "latest",
"cookie-es": "^1.0.0",
"defu": "^6.1.3",
Expand All @@ -49,12 +49,11 @@
},
"devDependencies": {
"@nuxt-alt/proxy": "^2.4.8",
"@nuxt/schema": "^3.8.2",
"@nuxt/ui": "^2.10.0",
"@nuxt/schema": "^3.9.1",
"@nuxtjs/i18n": "next",
"@types/node": "^20",
"jiti": "^1.21.0",
"nuxt": "^3.9.0",
"nuxt": "^3.9.1",
"typescript": "^5.3.3",
"unbuild": "^2.0.0"
},
Expand Down
7 changes: 3 additions & 4 deletions src/runtime/core/auth.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { HTTPRequest, HTTPResponse, Scheme, SchemeCheck, TokenableScheme, RefreshableScheme, ModuleOptions, Route, AuthState, } from '../../types';
import { ExpiredAuthSessionError } from '../inc/expired-auth-session-error';
import type { NuxtApp } from '#app';
import type { Router } from 'vue-router';
import { isSet, getProp, isRelativeURL, routeMeta, hasOwn } from '../../utils';
import { Storage } from './storage';
import { isSamePath, withQuery } from 'ufo';
Expand Down Expand Up @@ -190,7 +189,7 @@ export class Auth {
const enableTokenValidation = !this.#tokenValidationInterval && this.refreshStrategy.token && this.options.tokenValidationInterval

this.$storage.watchState('loggedIn', (loggedIn: boolean) => {
if (hasOwn((this.ctx.$router as Router).currentRoute.value.meta, 'auth') && !routeMeta((this.ctx.$router as Router).currentRoute.value, 'auth', false)) {
if (hasOwn(this.ctx.$router.currentRoute.value.meta, 'auth') && !routeMeta(this.ctx.$router.currentRoute.value, 'auth', false)) {
this.redirect(loggedIn ? 'home' : 'logout');
}

Expand Down Expand Up @@ -448,7 +447,7 @@ export class Auth {
return;
}

const currentRoute = (this.ctx.$router as Router).currentRoute.value;
const currentRoute = this.ctx.$router.currentRoute.value;
const nuxtRoute = this.options.fullPathRedirect ? currentRoute.fullPath : currentRoute.path
const from = route ? (this.options.fullPathRedirect ? route.fullPath : route.path) : nuxtRoute;

Expand Down Expand Up @@ -498,7 +497,7 @@ export class Auth {
return globalThis.location.replace(to)
}
else {
return (this.ctx.$router as Router).push(typeof this.ctx.$localePath === 'function' ? this.ctx.$localePath(to) : to);
return this.ctx.$router.push(typeof this.ctx.$localePath === 'function' ? this.ctx.$localePath(to) : to);
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/runtime/inc/configuration-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import { Storage } from '../core/storage';
import { defu } from 'defu';

// eslint-disable-next-line no-console
const ConfigurationDocumentWarning = (message: string) =>
console.warn(`[AUTH] [OPENID CONNECT] Invalid configuration. ${message}`);
const ConfigurationDocumentWarning = (message: string) => console.warn(`[AUTH] [OPENID CONNECT] Invalid configuration. ${message}`);

/**
* A metadata document that contains most of the OpenID Provider's information,
Expand Down
2 changes: 2 additions & 0 deletions src/runtime/inc/default-properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const OAUTH2DEFAULTS = {
maxAge: 1800,
prefix: '_id_token.',
expirationPrefix: '_id_token_expiration.',
httpOnly: false,
},
refreshToken: {
property: 'refresh_token',
Expand Down Expand Up @@ -84,6 +85,7 @@ export const LOCALDEFAULTS = {
required: true,
prefix: '_token.',
expirationPrefix: '_token_expiration.',
httpOnly: false
},
refreshToken: {
property: 'refresh_token',
Expand Down
27 changes: 18 additions & 9 deletions src/runtime/inc/id-token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,32 +28,41 @@ export class IdToken {
return idToken;
}

sync(): string | boolean {
sync(): string | boolean | void | null | undefined {
const idToken = this.#syncToken();
this.#syncExpiration();

return idToken;
}

reset() {
this.#setToken(false);
this.#setExpiration(false);
this.scheme.requestHandler!.clearHeader();
this.#resetSSRToken();
this.#setToken(undefined);
this.#setExpiration(undefined);
}

status(): TokenStatus {
return new TokenStatus(this.get(), this.#getExpiration());
}

#resetSSRToken(): void {
if (this.scheme.options.ssr && this.scheme.options.idToken?.httpOnly) {
const key = this.scheme.options.idToken!.prefix + this.scheme.name;
this.scheme.$auth.request({ baseURL: '', url: '/_auth/reset', body: new URLSearchParams({ token: key }), method: 'POST' })
}
}

#getExpiration(): number | false {
const key = this.scheme.options.idToken.expirationPrefix + this.scheme.name;

return this.$storage.getUniversal(key) as number | false;
}

#setExpiration(expiration: number | false): number | false {
#setExpiration(expiration: number | false | undefined | null): number | false | void | null | undefined {
const key = this.scheme.options.idToken.expirationPrefix + this.scheme.name;

return this.$storage.setUniversal(key, expiration) as number | false;
return this.$storage.setUniversal(key, expiration);
}

#syncExpiration(): number | false {
Expand All @@ -63,7 +72,7 @@ export class IdToken {
return this.$storage.syncUniversal(key) as number | false;
}

#updateExpiration(idToken: string | boolean): number | false | void {
#updateExpiration(idToken: string | boolean): number | false | void | null | undefined {
let idTokenExpiration: number;
const tokenIssuedAtMillis = Date.now();
const tokenTTLMillis = Number(this.scheme.options.idToken.maxAge) * 1000;
Expand All @@ -85,16 +94,16 @@ export class IdToken {
return this.#setExpiration(idTokenExpiration || false);
}

#setToken(idToken: string | boolean): string | boolean {
#setToken(idToken: string | boolean | undefined | null): string | boolean | void | null | undefined {
const key = this.scheme.options.idToken.prefix + this.scheme.name;

return this.$storage.setUniversal(key, idToken) as string | boolean;
}

#syncToken(): string | boolean {
#syncToken(): string | boolean | void | null | undefined {
const key = this.scheme.options.idToken.prefix + this.scheme.name;

return this.$storage.syncUniversal(key) as string | boolean;
return this.$storage.syncUniversal(key)
}

userInfo() {
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/inc/request-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ export class RequestHandler {
initializeRequestInterceptor(refreshEndpoint?: string | Request): void {
this.requestInterceptor = this.http.onRequest(
async (config: FetchConfig) => {
// Set the token on the client side
if (this.scheme.options.token && this.scheme.options.token.httpOnly && this.currentToken) {
// Set the token on the client side if not set
if (this.scheme.options.token && this.currentToken) {
this.setHeader(this.currentToken)
}

Expand Down
6 changes: 3 additions & 3 deletions src/runtime/schemes/oauth2.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { RefreshableScheme, SchemePartialOptions, SchemeCheck, RefreshableSchemeOptions, UserOptions, SchemeOptions, HTTPResponse, EndpointsOption, TokenableSchemeOptions } from '../../types';
import type { IncomingMessage } from 'node:http';
import type { Auth } from '../core';
import type { Router } from 'vue-router';
import { getProp, normalizePath, randomString, removeTokenPrefix, parseQuery } from '../../utils';
import { RefreshController, RequestHandler, ExpiredAuthSessionError, Token, RefreshToken } from '../inc';
import { joinURL, withQuery } from 'ufo';
Expand Down Expand Up @@ -66,6 +65,7 @@ const DEFAULTS: SchemePartialOptions<Oauth2SchemeOptions> = {
global: true,
prefix: '_token.',
expirationPrefix: '_token_expiration.',
httpOnly: false
},
refreshToken: {
property: 'refresh_token',
Expand Down Expand Up @@ -352,7 +352,7 @@ export class Oauth2Scheme<OptionsT extends Oauth2SchemeOptions = Oauth2SchemeOpt
}

async #handleCallback(): Promise<boolean | void> {
const route = (this.$auth.ctx.$router as Router).currentRoute.value
const route = this.$auth.ctx.$router.currentRoute.value

// Handle callback only for specified route
if (this.$auth.options.redirect && normalizePath(route.path, this.$auth.ctx) !== normalizePath(this.$auth.options.redirect.callback as string, this.$auth.ctx)) {
Expand Down Expand Up @@ -404,7 +404,7 @@ export class Oauth2Scheme<OptionsT extends Oauth2SchemeOptions = Oauth2SchemeOpt
},
body: new URLSearchParams({
code: parsedQuery.code as string,
client_id: this.options.clientId as string,
client_id: this.options.clientId,
redirect_uri: this.redirectURI,
response_type: this.options.responseType,
audience: this.options.audience,
Expand Down
3 changes: 2 additions & 1 deletion src/runtime/schemes/openIDConnect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const DEFAULTS: SchemePartialOptions<OpenIDConnectSchemeOptions> = {
maxAge: 1800,
prefix: '_id_token.',
expirationPrefix: '_id_token_expiration.',
httpOnly: false,
},
fetchRemote: false,
codeChallengeMethod: 'S256',
Expand Down Expand Up @@ -175,7 +176,7 @@ export class OpenIDConnectScheme<OptionsT extends OpenIDConnectSchemeOptions = O
}

async #handleCallback() {
const route = (this.$auth.ctx.$router as Router).currentRoute.value;
const route = this.$auth.ctx.$router.currentRoute.value;

// Handle callback only for specified route
if (this.$auth.options.redirect && normalizePath(route.path, this.$auth.ctx) !== normalizePath(this.$auth.options.redirect.callback as string, this.$auth.ctx)) {
Expand Down
5 changes: 1 addition & 4 deletions src/runtime/schemes/refresh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,10 @@ export class RefreshScheme<OptionsT extends RefreshSchemeOptions = RefreshScheme
}

// Add grant type to payload if defined
if (this.options.grantType) {
endpoint.body!.grant_type = 'refresh_token';
}
endpoint.body!.grant_type = 'refresh_token';

cleanObj(endpoint.body!);

// @ts-ignore
if (this.options.ssr) {
endpoint.baseURL = ''
}
Expand Down
6 changes: 6 additions & 0 deletions src/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ declare module '#app' {
}
}

declare module 'vue-router' {
interface RouteMeta {
auth?: 'guest' | false
}
}

declare module '@nuxt/schema' {
interface NuxtConfig {
['auth']?: Partial<ModuleOptions>
Expand Down
76 changes: 75 additions & 1 deletion src/types/options.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,83 @@ import type { CookieSerializeOptions } from 'cookie-es';
import type { Auth } from '../runtime'

export interface ModuleOptions {
/**
* Whether the global middleware is enabled or not.
* This option is disabled if `enableMiddleware` is `false`
*/
globalMiddleware?: boolean;

/**
* Whether middleware is enabled or not.
*/
enableMiddleware?: boolean;

/**
* Plugins to be used by the module.
*/
plugins?: (NuxtPlugin | string)[];

/**
* Authentication strategies used by the module.
*/
strategies?: Record<string, Strategy>;

/**
* Whether exceptions should be ignored or not.
*/
ignoreExceptions: boolean;

/**
* Whether the auth module should reset login data on an error.
*/
resetOnError: boolean | ((...args: any[]) => boolean);

/**
* Whether to reset on a response error.
*/
resetOnResponseError: boolean | ((error: any, auth: Auth, scheme: TokenableScheme | RefreshableScheme) => void);

/**
* Default authentication strategy to be used by the module.
* This is used internally.
*/
defaultStrategy: string | undefined;

/**
* Whether to watch user logged in state or not.
*/
watchLoggedIn: boolean;

/**
* Interval for token validation.
*/
tokenValidationInterval: boolean | number;

/**
* Whether to rewrite redirects or not.
*/
rewriteRedirects: boolean;

/**
* Whether to redirect with full path or not.
*/
fullPathRedirect: boolean;

/**
* Redirect strategy to be used: 'query' or 'storage'
*/
redirectStrategy?: 'query' | 'storage';

/**
* Key for scope.
*/
scopeKey: string;

/**
* Store options for the auth module. The `pinia` store will not
* be utilized unless you enable it. By default `useState()` will be
* used instead.
*/
stores: Partial<{
state: {
namespace?: string
Expand All @@ -40,12 +103,23 @@ export interface ModuleOptions {
enabled?: boolean;
prefix?: string;
};
}>,
}>;

/**
* Redirect URL for login, logout, callback and home.
*
* *Note:* The `trans` argument is only available if
* `nuxt/i18n` is available.
*/
redirect: {
login: string | ((auth: Auth, trans?: Function) => string);
logout: string | ((auth: Auth, trans?: Function) => string);
callback: string | ((auth: Auth, trans?: Function) => string);
home: string | ((auth: Auth, trans?: Function) => string);
};

/**
* Initial state for Auth. This is used Internally.
*/
initialState?: AuthState;
}
2 changes: 1 addition & 1 deletion src/types/router.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { RouteLocationNormalized } from 'vue-router'
import type { RouteLocationNormalized } from '#vue-router'

export type Route = RouteLocationNormalized;
export interface RedirectRouterOptions {
Expand Down
Loading

0 comments on commit ea5d9b8

Please sign in to comment.