diff --git a/README.md b/README.md
index 46563564..b314d718 100644
--- a/README.md
+++ b/README.md
@@ -62,7 +62,7 @@ Nuxt Auth Utils automatically adds some plugins to fetch the current user sessio
```vue
@@ -74,6 +74,8 @@ const { loggedIn, user, session, fetch, clear } = useUserSession()
```
@@ -106,6 +108,10 @@ interface UserSessionComposable {
* Clear the user session and remove the session cookie.
*/
clear: () => Promise
+ /**
+ * Open the OAuth route in a popup that auto-closes when successful.
+ */
+ openInPopup: (route: string, size?: { width?: number, height?: number }) => void
}
```
diff --git a/playground/app.vue b/playground/app.vue
index 5fdbd2c2..1ad0c2ca 100644
--- a/playground/app.vue
+++ b/playground/app.vue
@@ -1,6 +1,7 @@
@@ -259,6 +262,14 @@ const providers = computed(() =>
+
+ Popup mode
+
diff --git a/src/runtime/app/composables/session.ts b/src/runtime/app/composables/session.ts
index fc569c98..eadc7c9f 100644
--- a/src/runtime/app/composables/session.ts
+++ b/src/runtime/app/composables/session.ts
@@ -38,12 +38,41 @@ export function useUserSession(): UserSessionComposable {
}
}
+ const popupListener = (e: StorageEvent) => {
+ if (e.key === 'temp-nuxt-auth-utils-popup') {
+ fetch()
+ window.removeEventListener('storage', popupListener)
+ }
+ }
+ const openInPopup = (route: string, size: { width?: number, height?: number } = {}) => {
+ // Set a local storage item to tell the popup that we pending auth
+ localStorage.setItem('temp-nuxt-auth-utils-popup', 'true')
+
+ const width = size.width ?? 960
+ const height = size.height ?? 600
+ const top = (window.top?.outerHeight ?? 0) / 2
+ + (window.top?.screenY ?? 0)
+ - height / 2
+ const left = (window.top?.outerWidth ?? 0) / 2
+ + (window.top?.screenX ?? 0)
+ - width / 2
+
+ window.open(
+ route,
+ 'nuxt-auth-utils-popup',
+ `width=${width}, height=${height}, top=${top}, left=${left}, toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no`,
+ )
+
+ window.addEventListener('storage', popupListener)
+ }
+
return {
ready: computed(() => authReadyState.value),
loggedIn: computed(() => Boolean(sessionState.value.user)),
user: computed(() => sessionState.value.user || null),
session: sessionState,
fetch,
+ openInPopup,
clear,
}
}
diff --git a/src/runtime/app/plugins/session.client.ts b/src/runtime/app/plugins/session.client.ts
index 13a2991d..146ccccb 100644
--- a/src/runtime/app/plugins/session.client.ts
+++ b/src/runtime/app/plugins/session.client.ts
@@ -12,4 +12,11 @@ export default defineNuxtPlugin(async (nuxtApp) => {
await useUserSession().fetch()
})
}
+
+ if (localStorage.getItem('temp-nuxt-auth-utils-popup')) {
+ // There is a local storage item. That's mean we are coming back in the popup
+ localStorage.removeItem('temp-nuxt-auth-utils-popup')
+ const error = useError()
+ if (!error.value) window.close()
+ }
})
diff --git a/src/runtime/types/session.ts b/src/runtime/types/session.ts
index 2533f674..e301da45 100644
--- a/src/runtime/types/session.ts
+++ b/src/runtime/types/session.ts
@@ -50,4 +50,8 @@ export interface UserSessionComposable {
* Clear the user session and remove the session cookie.
*/
clear: () => Promise
+ /**
+ * Open the OAuth route in a popup that auto-closes when successful.
+ */
+ openInPopup: (route: string, size?: { width?: number, height?: number }) => void
}