Skip to content

Commit

Permalink
feat(oidc): ✨ Added handling for providers that don't refresh the ref…
Browse files Browse the repository at this point in the history
…resh token
  • Loading branch information
itpropro committed Sep 22, 2024
1 parent 2ba5604 commit 55230a2
Show file tree
Hide file tree
Showing 25 changed files with 839 additions and 1,117 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"defu": "^6.1.4",
"h3": "^1.12.0",
"jose": "^5.9.2",
"ofetch": "^1.3.4",
"ofetch": "^1.4.0",
"scule": "^1.3.0",
"sirv": "^2.0.4",
"ufo": "^1.5.4",
Expand Down
18 changes: 0 additions & 18 deletions playground/staticwebapp.config.json

This file was deleted.

1,227 changes: 475 additions & 752 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

191 changes: 62 additions & 129 deletions src/module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { OidcProviderConfig, ProviderConfigs, ProviderKeys } from './runtime/types/oidc'
import type { AuthSessionConfig } from './runtime/types/session'
import type { ProviderInfo } from './types'
import type { OidcProviderConfig } from './runtime/server/utils/provider'
import type { AuthSessionConfig, DevModeConfig, MiddlewareConfig, ProviderConfigs, ProviderKeys } from './runtime/types'
import { extendServerRpc, onDevToolsInitialized } from '@nuxt/devtools-kit'
import { addImportsDir, addPlugin, addRouteMiddleware, addServerHandler, addServerPlugin, createResolver, defineNuxtModule, extendRouteRules, useLogger } from '@nuxt/kit'
import { defu } from 'defu'
Expand All @@ -10,124 +9,39 @@ import { generateProviderUrl } from './runtime/server/utils/config'

const RPC_NAMESPACE = 'nuxt-oidc-auth-rpc'

export interface ServerFunctions {
interface ServerFunctions {
getNuxtOidcAuthSecrets: () => Record<'tokenKey' | 'sessionSecret' | 'authSessionSecret', string>
}

export interface ClientFunctions {
showNotification: (message: string) => void
}

export interface MiddlewareConfig {
/**
* Enables/disables the global middleware
* @default true
*/
globalMiddlewareEnabled?: boolean
/**
* Enables/disables automatic registration of '/auth/login' and '/auth/logout' route rules
* @default false
*/
customLoginPage?: boolean
}

export interface DevModeConfig {
/**
* Enables/disables the dev mode. Dev mode can only be enabled when the app runs in a non production environment.
* @default false
*/
enabled?: boolean
/**
* Sets the `userName` field on the user object
* @default 'Nuxt OIDC Auth Dev'
*/
userName?: string
/**
* Sets the `providerInfo` field on the user object
*/
providerInfo?: ProviderInfo
/**
* Sets the key algorithm for signing the generated JWT token
*/
tokenAlgorithm?: 'symmetric' | 'asymmetric'
/**
* Sets the `idToken` field on the user object
*/
idToken?: string
/**
* Sets the `accessToken` field on the user object
*/
accessToken?: string
/**
* Sets the claims field on the user object and generated JWT token if `generateAccessToken` is set to `true`.
*/
claims?: Record<string, string>
/**
* If set generates a JWT token for the access_token field based on the given user information
* @default false
*/
generateAccessToken?: boolean
/**
* Only used with `generateAccessToken`. Sets the issuer field on the generated JWT token.
* @default 'nuxt:oidc:auth:issuer
*/
issuer?: string
/**
* Only used with `generateAccessToken`. Sets the audience field on the generated JWT token.
* @default 'nuxt:oidc:auth:audience
*/
audience?: string
/**
* Only used with `generateAccessToken`. Sets the subject field on the generated JWT token.
* @default 'nuxt:oidc:auth:subject
*/
subject?: string
}
interface ClientFunctions {}

export interface ModuleOptions {
/**
* Enable module
*/
enabled: boolean
/**
* Enable Nuxt devtools integration
* @default true
*/
devtools?: boolean
/**
* Default provider. Will be used with composable if no provider is specified
*/
defaultProvider?: ProviderKeys
/**
* OIDC providers
*/
providers: Partial<ProviderConfigs>
/**
* Optional session configuration.
*/
session: AuthSessionConfig
/**
* Middleware configuration
*/
middleware: MiddlewareConfig
/**
* Dev mode configuration
*/
devMode?: DevModeConfig
/**
* Provide defaults for NUXT_OIDC_SESSION_SECRET, NUXT_OIDC_TOKEN_KEY and NUXT_OIDC_AUTH_SESSION_SECRET using a Nitro plugin. Turning this off can lead to the app not working if no secrets are provided.
* @default true
*/
provideDefaultSecrets?: boolean
}
const { resolve } = createResolver(import.meta.url)

declare module '@nuxt/schema' {
interface RuntimeConfig {
oidc: ModuleOptions
}
}

const { resolve } = createResolver(import.meta.url)
const DEFAULTS: ModuleOptions = {
enabled: true,
session: {
automaticRefresh: true,
expirationCheck: true,
maxAge: 60 * 60 * 24, // 1 day
cookie: {
sameSite: 'lax',
secure: process.env.NODE_ENV === 'production',
},
},
providers: {} as ProviderConfigs,
middleware: {
globalMiddlewareEnabled: true,
customLoginPage: false,
},
provideDefaultSecrets: true,
devtools: true,
}

export default defineNuxtModule<ModuleOptions>({
meta: {
Expand All @@ -138,25 +52,7 @@ export default defineNuxtModule<ModuleOptions>({
bridge: false,
},
},
defaults: {
enabled: true,
session: {
automaticRefresh: true,
expirationCheck: true,
maxAge: 60 * 60 * 24, // 1 day
cookie: {
sameSite: 'lax',
secure: process.env.NODE_ENV === 'production',
},
},
providers: {} as ProviderConfigs,
middleware: {
globalMiddlewareEnabled: true,
customLoginPage: false,
},
provideDefaultSecrets: true,
devtools: true,
},
defaults: DEFAULTS,
setup(options, nuxt) {
const logger = useLogger('nuxt-oidc-auth')
if (!options.enabled)
Expand Down Expand Up @@ -336,3 +232,40 @@ export default defineNuxtModule<ModuleOptions>({
)
},
})

export interface ModuleOptions {
/**
* Enable module
*/
enabled: boolean
/**
* Enable Nuxt devtools integration
* @default true
*/
devtools?: boolean
/**
* Default provider. Will be used with composable if no provider is specified
*/
defaultProvider?: ProviderKeys
/**
* OIDC providers
*/
providers: Partial<ProviderConfigs>
/**
* Optional session configuration.
*/
session: AuthSessionConfig
/**
* Middleware configuration
*/
middleware: MiddlewareConfig
/**
* Dev mode configuration
*/
devMode?: DevModeConfig
/**
* Provide defaults for NUXT_OIDC_SESSION_SECRET, NUXT_OIDC_TOKEN_KEY and NUXT_OIDC_AUTH_SESSION_SECRET using a Nitro plugin. Turning this off can lead to the app not working if no secrets are provided.
* @default true
*/
provideDefaultSecrets?: boolean
}
3 changes: 1 addition & 2 deletions src/runtime/composables/oidcAuth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { ComputedRef, Ref } from '#imports'
import type { ProviderKeys } from '../types/oidc'
import type { UserSession } from '../types/session'
import type { ProviderKeys, UserSession } from '../types'
import { computed, navigateTo, useRequestFetch, useState } from '#imports'

const useSessionState = () => useState<UserSession>('nuxt-oidc-auth-session', undefined)
Expand Down
3 changes: 1 addition & 2 deletions src/runtime/middleware/oidcAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ export default defineNuxtRouteMiddleware(async (to: RouteLocationNormalized) =>
if (isErrorPage) {
return
}

const { loggedIn, login } = useOidcAuth()

if (loggedIn.value === true || to.path.startsWith('/auth')) {
if (loggedIn.value === true || to.path.startsWith('/auth/')) {
return
}
await login()
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/providers/apple.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { OidcProviderConfig } from '../types/oidc'
import { defineOidcProvider } from './provider'
import type { OidcProviderConfig } from '../server/utils/provider'
import { defineOidcProvider } from '../server/utils/provider'

type AppleRequiredFields = 'clientId' | 'clientSecret' | 'authorizationUrl' | 'tokenUrl' | 'redirectUri'

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/providers/auth0.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ofetch } from 'ofetch'
import { normalizeURL, withHttps, withoutTrailingSlash } from 'ufo'
import { defineOidcProvider } from './provider'
import { defineOidcProvider } from '../server/utils/provider'

interface Auth0ProviderConfig {
connection?: string
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/providers/entra.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ofetch } from 'ofetch'
import { parseURL } from 'ufo'
import { defineOidcProvider } from './provider'
import { defineOidcProvider } from '../server/utils/provider'

type EntraIdRequiredFields = 'clientId' | 'clientSecret' | 'authorizationUrl' | 'tokenUrl' | 'redirectUri'

Expand Down
4 changes: 2 additions & 2 deletions src/runtime/providers/github.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { OidcProviderConfig } from '../types/oidc'
import { defineOidcProvider } from './provider'
import type { OidcProviderConfig } from '../server/utils/provider'
import { defineOidcProvider } from '../server/utils/provider'

type GithubRequiredFields = 'clientId' | 'clientSecret' | 'redirectUri'

Expand Down
11 changes: 6 additions & 5 deletions src/runtime/providers/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { auth0 } from './auth0'
export { entra } from './entra'
export { github } from './github'
export { keycloak } from './keycloak'
export { oidc } from './oidc'
export { apple } from './apple.js'
export { auth0 } from './auth0.js'
export { entra } from './entra.js'
export { github } from './github.js'
export { keycloak } from './keycloak.js'
export { oidc } from './oidc.js'
2 changes: 1 addition & 1 deletion src/runtime/providers/keycloak.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ofetch } from 'ofetch'
import { generateProviderUrl } from '../server/utils/config'
import { defineOidcProvider } from './provider'
import { defineOidcProvider } from '../server/utils/provider'

type KeycloakRequiredFields = 'baseUrl' | 'clientId' | 'clientSecret' | 'redirectUri'

Expand Down
4 changes: 2 additions & 2 deletions src/runtime/providers/oidc.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { OidcProviderConfig } from '../types/oidc'
import { defineOidcProvider } from './provider'
import type { OidcProviderConfig } from '../server/utils/provider'
import { defineOidcProvider } from '../server/utils/provider'

type OidcRequiredFields = 'clientId' | 'clientSecret' | 'authorizationUrl' | 'tokenUrl' | 'redirectUri'

Expand Down
47 changes: 0 additions & 47 deletions src/runtime/providers/provider.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/runtime/server/handler/callback.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { UserSession } from '../../types/session'
import type { UserSession } from '../../types'
import { sendRedirect } from 'h3'
import { callbackEventHandler } from '../lib/oidc'
import { setUserSession } from '../utils/session'
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/server/handler/dev.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { UserSession } from '../../types/session'
import type { UserSession } from '../../types'
import { sendRedirect } from 'h3'
import { devEventHandler } from '../lib/oidc'
import { setUserSession } from '../utils/session'
Expand Down
Loading

0 comments on commit 55230a2

Please sign in to comment.