diff --git a/playground/nuxt.config.ts b/playground/nuxt.config.ts
index 62818c6..8e4b44f 100644
--- a/playground/nuxt.config.ts
+++ b/playground/nuxt.config.ts
@@ -43,12 +43,15 @@ export default defineNuxtConfig({
clientSecret: 'secret',
callbackUrl: '',
scope: [
+ 'openid',
'email',
- 'profile'
+ 'profile',
+ // 'address'
]
},
config: {
- response_type: 'id_token',
+ debug: true,
+ response_type: 'code',
secret: 'oidc._sessionid',
cookie: { loginName: '' },
cookiePrefix: 'oidc._',
diff --git a/playground/pages/[...slug].vue b/playground/pages/[...slug].vue
new file mode 100644
index 0000000..986a301
--- /dev/null
+++ b/playground/pages/[...slug].vue
@@ -0,0 +1,11 @@
+
+
+
+
+ 401 Unauthenticated
+
+
+
+
+
diff --git a/playground/pages/public.vue b/playground/pages/public.vue
index 8393c84..242966f 100644
--- a/playground/pages/public.vue
+++ b/playground/pages/public.vue
@@ -2,6 +2,7 @@
+ Public Page
You should see this page without need to authentication!
diff --git a/playground/pages/secure.vue b/playground/pages/secure.vue
index 8393c84..b59463d 100644
--- a/playground/pages/secure.vue
+++ b/playground/pages/secure.vue
@@ -2,12 +2,18 @@
+ Secure Page
- You should see this page without need to authentication!
+ Secured content
+ You should see this page only if authenticated!
-
diff --git a/src/module.ts b/src/module.ts
index 7b1480f..1c05f8c 100644
--- a/src/module.ts
+++ b/src/module.ts
@@ -1,7 +1,9 @@
import { fileURLToPath } from 'url'
-import { defineNuxtModule, addPlugin, resolveModule, createResolver } from '@nuxt/kit'
+import { defineNuxtModule, addPlugin, resolveModule, createResolver } from '@nuxt/kit';
import defu from 'defu'
import { name, version } from '../package.json'
+import { logger } from './runtime/utils/logger';
+
export type CookieSerializeOptions = {
domain?: string | undefined;
@@ -35,6 +37,7 @@ export type Config = {
cookieFlags?: {
[key: string]: CookieSerializeOptions,
}
+ debug?: boolean | undefined,
}
export interface ModuleOptions {
@@ -61,13 +64,11 @@ export default defineNuxtModule({
clientSecret: '',
callbackUrl: '',
scope: [
- 'email',
- 'profile',
- 'address'
]
},
// express-session configuration
config: {
+ debug: false,
secret: 'oidc._sessionid', // process.env.OIDC_SESSION_SECRET
cookie: {},
cookiePrefix: 'oidc._',
@@ -80,8 +81,12 @@ export default defineNuxtModule({
cookieFlags: {}
}
},
- setup (options, nuxt) {
- // console.log(options.op)
+ setup(options, nuxt) {
+ logger.level = options.config.debug == true ? 5 : 0 // 4 = debug, 5 = trace
+ logger.info('[DEBUG MODE]: ', options.config.debug);
+ logger.debug('[WITHOUT ENV VARS] options:', options);
+
+
const { resolve } = createResolver(import.meta.url)
const resolveRuntimeModule = (path: string) => resolveModule(path, { paths: resolve('./runtime') })
@@ -144,4 +149,4 @@ export default defineNuxtModule({
addPlugin(resolve(runtimeDir, 'plugin'))
}
}
-})
+})
\ No newline at end of file
diff --git a/src/runtime/plugin.ts b/src/runtime/plugin.ts
index f009ff0..5ee849a 100644
--- a/src/runtime/plugin.ts
+++ b/src/runtime/plugin.ts
@@ -3,6 +3,7 @@ import { Storage, StorageOptions } from './storage'
import { isUnset, isSet } from './utils/utils'
import { encrypt, decrypt } from './utils/encrypt'
import { useState, useFetch, useRuntimeConfig, useCookie } from '#imports'
+import { logger } from '@nuxt/kit'
interface UseState {
user: any,
@@ -14,7 +15,7 @@ class Oidc {
private $useState: any // State: Nuxt.useState (share state in all nuxt pages and components) https://v3.nuxtjs.org/guide/features/state-management
public $storage: Storage // LocalStorage: Browser.localStorage (share state in all sites, use in page refresh.)
- constructor () {
+ constructor() {
this.state = { user: {}, isLoggedIn: false }
this.$useState = useState('useState', () => { return { user: {}, isLoggedIn: false } })
@@ -29,7 +30,7 @@ class Oidc {
this.$storage = storage
}
- get user () {
+ get user() {
const userInfoState = this.$useState.value.user
const userInfoLS = this.$storage.getUserInfo()
if ((isUnset(userInfoState))) {
@@ -42,14 +43,14 @@ class Oidc {
// return this.state.user // not auto update
}
- get isLoggedIn () {
+ get isLoggedIn() {
const isLoggedIn = this.$useState.value.isLoggedIn
const isLoggedInLS = this.$storage.isLoggedIn()
// console.log('isLoggedIn', isLoggedIn, isLoggedInLS)
return isLoggedIn || isLoggedInLS
}
- setUser (user: any) {
+ setUser(user: any) {
this.state.user = user
this.state.isLoggedIn = Object.keys(user).length > 0
@@ -59,7 +60,7 @@ class Oidc {
this.$storage.setUserInfo(user)
}
- async fetchUser () {
+ async fetchUser() {
try {
if (process.server) {
console.log('serve-render: fetchUser from cookie.')
@@ -93,7 +94,7 @@ class Oidc {
}
}
- login (redirect = '/') {
+ login(redirect = '/') {
if (process.client) {
const params = new URLSearchParams({ redirect })
const toStr = '/oidc/login' // + params.toString()
@@ -102,7 +103,7 @@ class Oidc {
}
}
- logout () {
+ logout() {
// TODO clear user info when accessToken expired.
if (process.client) {
this.$useState.value.user = {}
@@ -115,8 +116,11 @@ class Oidc {
}
export default defineNuxtPlugin((nuxtApp) => {
+ // TODO: enable consola debug mode here instead of console.log
console.log('--- Nuxt plugin: nuxt-openid-connect!')
const oidc = new Oidc()
nuxtApp.provide('oidc', oidc)
+ // console.log('--- Nuxt plugin: DEBUG MODE:' + useNuxtApp().ssrContext?.runtimeConfig.openidConnect.config.debug);
+
oidc.fetchUser() // render both from server and client.
})
diff --git a/src/runtime/server/routes/oidc/callback.ts b/src/runtime/server/routes/oidc/callback.ts
index 81b451f..62ed6de 100644
--- a/src/runtime/server/routes/oidc/callback.ts
+++ b/src/runtime/server/routes/oidc/callback.ts
@@ -2,9 +2,10 @@ import { defineEventHandler, getCookie, setCookie } from 'h3'
import { initClient } from '../../../utils/issueclient'
import { encrypt } from '../../../utils/encrypt'
import { useRuntimeConfig } from '#imports'
+import { logger } from '../../../utils/logger'
export default defineEventHandler(async (event) => {
- console.log('oidc/callback calling')
+ logger.debug('[CALLBACK]: oidc/callback calling')
const { op, config } = useRuntimeConfig().openidConnect
const sessionid = getCookie(event, config.secret)
const req = event.node.req
@@ -14,19 +15,21 @@ export default defineEventHandler(async (event) => {
const callBackUrl = op.callbackUrl.replace('cbt', 'callback')
if (params.access_token) {
+ logger.debug('[CALLBACK]: has access_token in params')
await getUserInfo(params.access_token)
} else if (params.code) {
+ logger.debug('[CALLBACK]: has code in params')
const tokenSet = await issueClient.callback(callBackUrl, params, { nonce: sessionid })
if (tokenSet.access_token) {
await getUserInfo(tokenSet.access_token)
}
} else {
- console.log('empty callback')
+ logger.debug('[CALLBACK]: empty callback')
}
res.writeHead(302, { Location: '/' })
res.end()
- async function getUserInfo (accessToken: string) {
+ async function getUserInfo(accessToken: string) {
try {
const userinfo = await issueClient.userinfo(accessToken)
setCookie(event, config.cookiePrefix + 'access_token', accessToken, {
@@ -45,7 +48,7 @@ export default defineEventHandler(async (event) => {
const encryptedText = await encrypt(JSON.stringify(userinfo), config)
setCookie(event, config.cookiePrefix + 'user_info', encryptedText, { ...config.cookieFlags['user_info' as keyof typeof config.cookieFlags] })
} catch (err) {
- console.log(err)
+ logger.error("[CALLBACK]: " + err)
}
}
})
diff --git a/src/runtime/server/routes/oidc/cbt.ts b/src/runtime/server/routes/oidc/cbt.ts
index 12bc49c..1ec6a5e 100644
--- a/src/runtime/server/routes/oidc/cbt.ts
+++ b/src/runtime/server/routes/oidc/cbt.ts
@@ -1,16 +1,17 @@
import { defineEventHandler, setCookie, getCookie } from 'h3'
import { CBT_PAGE_TEMPATE } from '../../../utils/template'
import { useRuntimeConfig } from '#imports'
+import { logger } from '@nuxt/kit'
export default defineEventHandler((event) => {
- console.log('oidc/cbt calling')
+ logger.debug('[CBT]: oidc/cbt calling')
const { config } = useRuntimeConfig().openidConnect
const res = event.res
const html = CBT_PAGE_TEMPATE
const sessionkey = config.secret
const sessionid = getCookie(event, sessionkey)
- // console.log(sessionid)
+ // logger.debug('[CBT]:' + sessionid)
/* setCookie(event, sessionkey, sessionid, {
maxAge: 24 * 60 * 60 // oneday
}) */
diff --git a/src/runtime/server/routes/oidc/login.ts b/src/runtime/server/routes/oidc/login.ts
index 1715b24..c187949 100644
--- a/src/runtime/server/routes/oidc/login.ts
+++ b/src/runtime/server/routes/oidc/login.ts
@@ -3,9 +3,10 @@ import { v4 as uuidv4 } from 'uuid'
import { initClient } from '../../../utils/issueclient'
import { useRuntimeConfig } from '#imports'
+import { logger } from '../../../utils/logger'
export default defineEventHandler(async (event) => {
- console.log('oidc/login calling')
+ logger.info('[Login]: oidc/login calling')
const { op, config } = useRuntimeConfig().openidConnect
const req = event.req
@@ -14,12 +15,12 @@ export default defineEventHandler(async (event) => {
const sessionkey = config.secret
let sessionid = getCookie(event, config.secret)
if (!sessionid) {
- // console.log('regenerate sessionid')
+ logger.trace('[Login]: regenerate sessionid')
sessionid = uuidv4()
}
const callbackUrl = (op.callbackUrl && op.callbackUrl.length > 0) ? op.callbackUrl : 'http://' + req.headers.host + '/oidc/cbt'
- // console.log('cabackurl:', callbackUrl, op.callbackUrl)
+ logger.trace('[Login]: cabackurl: ', callbackUrl, op.callbackUrl)
const parameters = {
redirect_uri: callbackUrl,
@@ -28,9 +29,9 @@ export default defineEventHandler(async (event) => {
scope: op.scope.join(' ') // 'openid' will be added by default
}
const authUrl = issueClient.authorizationUrl(parameters)
- // console.log(authUrl)
+ logger.trace('[Login]: Auth Url: ' + authUrl)
- console.log(sessionid)
+ logger.debug('[Login]: sessionid: ' + sessionid)
if (sessionid) {
setCookie(event, sessionkey, sessionid, {
maxAge: config.cookieMaxAge,
diff --git a/src/runtime/server/routes/oidc/logout.ts b/src/runtime/server/routes/oidc/logout.ts
index 12e04e6..99ba9e2 100644
--- a/src/runtime/server/routes/oidc/logout.ts
+++ b/src/runtime/server/routes/oidc/logout.ts
@@ -1,9 +1,10 @@
import { getCookie, deleteCookie, defineEventHandler } from 'h3'
import { useRuntimeConfig } from '#imports'
+import { logger } from '../../../utils/logger'
export default defineEventHandler((event) => {
const res = event.res
- console.log('oidc/logout calling')
+ logger.log('[LOGOUT]: oidc/logout calling')
const { config } = useRuntimeConfig().openidConnect
deleteCookie(event, config.secret)
diff --git a/src/runtime/server/routes/oidc/user.ts b/src/runtime/server/routes/oidc/user.ts
index d5c90ee..78ee8aa 100644
--- a/src/runtime/server/routes/oidc/user.ts
+++ b/src/runtime/server/routes/oidc/user.ts
@@ -2,11 +2,12 @@ import { getCookie, deleteCookie, defineEventHandler } from 'h3'
import { initClient } from '../../../utils/issueclient'
import { encrypt, decrypt } from '../../../utils/encrypt'
import { useRuntimeConfig } from '#imports'
+import { logger } from '../../../utils/logger'
export default defineEventHandler(async (event) => {
const { config, op } = useRuntimeConfig().openidConnect
- console.log('oidc/user calling')
- // console.log(req.headers.cookie)
+ logger.debug('[USER]: oidc/user calling')
+ logger.trace('[USER]: ' + event.req.headers.cookie)
const sessionid = getCookie(event, config.secret)
const accesstoken = getCookie(event, config.cookiePrefix + 'access_token')
@@ -30,7 +31,7 @@ export default defineEventHandler(async (event) => {
}
return userinfo
} catch (err) {
- console.log(err)
+ logger.error('[USER]: ' + err)
deleteCookie(event, config.secret)
deleteCookie(event, config.cookiePrefix + 'access_token')
deleteCookie(event, config.cookiePrefix + 'user_info')
@@ -43,7 +44,7 @@ export default defineEventHandler(async (event) => {
return {}
}
} else {
- console.log('empty accesstoken for access userinfo')
+ logger.debug('[USER]: empty accesstoken for access userinfo')
return {}
}
})
diff --git a/src/runtime/storage.ts b/src/runtime/storage.ts
index 9280563..b4b3f80 100644
--- a/src/runtime/storage.ts
+++ b/src/runtime/storage.ts
@@ -1,28 +1,28 @@
import { isUnset, isSet } from './utils/utils'
export type StorageOptions = {
- localStorage: boolean,
- prefix: string,
- ignoreExceptions: boolean
+ localStorage: boolean,
+ prefix: string,
+ ignoreExceptions: boolean
}
export class Storage {
public options: StorageOptions
private userInfoKey: string
- constructor (options: StorageOptions) {
+ constructor(options: StorageOptions) {
this.options = options
this.userInfoKey = 'user'
}
- getPrefix (): string {
+ getPrefix(): string {
if (!this.options.localStorage) {
throw new Error('Cannot get prefix; localStorage is off')
}
return this.options.prefix
}
- setUserInfo (user:any) {
+ setUserInfo(user: any) {
if (isUnset(user)) {
return
}
@@ -35,7 +35,7 @@ export class Storage {
this.setLocalStorage(this.userInfoKey, _userValue)
}
- getUserInfo (): any {
+ getUserInfo(): any {
if (this.isLocalStorageEnabled()) {
const _user = this.getLocalStorage(this.userInfoKey)
try {
@@ -48,18 +48,18 @@ export class Storage {
}
}
- removeUserInfo (): void {
+ removeUserInfo(): void {
if (this.isLocalStorageEnabled()) {
this.removeLocalStorage(this.userInfoKey)
}
}
- isLoggedIn (): boolean {
+ isLoggedIn(): boolean {
const user = this.getUserInfo()
return isSet(user) && Object.keys(user).length > 0
}
- setLocalStorage (key: string, value: string): string | void {
+ setLocalStorage(key: string, value: string): string | void {
// Unset null, undefined
if (isUnset(value)) {
return this.removeLocalStorage(key)
@@ -82,7 +82,7 @@ export class Storage {
return value
}
- getLocalStorage (key: string): string {
+ getLocalStorage(key: string): string {
if (!this.isLocalStorageEnabled()) {
return
}
@@ -94,7 +94,7 @@ export class Storage {
return value
}
- removeLocalStorage (key: string): void {
+ removeLocalStorage(key: string): void {
if (!this.isLocalStorageEnabled()) {
return
}
@@ -104,7 +104,7 @@ export class Storage {
}
// origin from https://github.com/nuxt-community/auth-module
- isLocalStorageEnabled (): boolean {
+ isLocalStorageEnabled(): boolean {
// Local Storage only exists in the browser
if (!process.client) {
return false
@@ -123,7 +123,7 @@ export class Storage {
// eslint-disable-next-line no-console
console.warn(
"[AUTH] Local storage is enabled in config, but browser doesn't" +
- ' support it'
+ ' support it'
)
}
return false
diff --git a/src/runtime/utils/issueclient.ts b/src/runtime/utils/issueclient.ts
index f2ae16c..e2d21ad 100644
--- a/src/runtime/utils/issueclient.ts
+++ b/src/runtime/utils/issueclient.ts
@@ -1,6 +1,8 @@
import { Issuer } from 'openid-client'
import { OidcProvider } from '../../module'
import { useRuntimeConfig } from '#imports'
+import { logger } from './logger'
+
export const initClient = async (op: OidcProvider, req: any) => {
const { config } = useRuntimeConfig().openidConnect
@@ -8,7 +10,7 @@ export const initClient = async (op: OidcProvider, req: any) => {
const callbackUrl = host ? 'http://' + host + '/oidc/cbt' : op.callbackUrl
const issuer = await Issuer.discover(op.issuer)
- // console.log('Discovered issuer %s %O', issuer.issuer, issuer.metadata)
+ logger.trace('Discovered issuer %s %O', issuer.issuer, issuer.metadata)
const client = new issuer.Client({
client_id: op.clientId,
client_secret: op.clientSecret,
diff --git a/src/runtime/utils/logger.ts b/src/runtime/utils/logger.ts
new file mode 100644
index 0000000..ca3367e
--- /dev/null
+++ b/src/runtime/utils/logger.ts
@@ -0,0 +1,20 @@
+import { logger as initLogger } from "@nuxt/kit"
+
+const getLevel = (): number => { // load
+ try {
+ return useRuntimeConfig().openidConnect.config.debug ? 4 : 0 // 5: trace, 4: debug, 0: errors
+ } catch (error) {
+ return 0
+ }
+}
+
+// Note: tag not working after nuxt ready
+const logger = initLogger.create({
+ // level: 5,
+ defaults: {
+ tag: 'nuxt-opentid',
+ },
+ level: getLevel(),
+})
+
+export { logger }
\ No newline at end of file
diff --git a/src/runtime/utils/template.ts b/src/runtime/utils/template.ts
index 2e21749..aaec716 100644
--- a/src/runtime/utils/template.ts
+++ b/src/runtime/utils/template.ts
@@ -1,3 +1,4 @@
+const debug = useRuntimeConfig().openidConnect.config.debug ?? false
export const CBT_PAGE_TEMPATE = `
@@ -8,7 +9,7 @@ export const CBT_PAGE_TEMPATE = `