cobras-auth-nuxt 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +302 -0
  2. package/dist/module.cjs +5 -0
  3. package/dist/module.d.mts +134 -0
  4. package/dist/module.d.ts +134 -0
  5. package/dist/module.json +12 -0
  6. package/dist/module.mjs +112 -0
  7. package/dist/runtime/components/CobrasDevTools.vue +89 -0
  8. package/dist/runtime/composables/useCobrasAuth.d.ts +0 -0
  9. package/dist/runtime/composables/useCobrasAuth.js +99 -0
  10. package/dist/runtime/composables/useCobrasDevTools.d.ts +0 -0
  11. package/dist/runtime/composables/useCobrasDevTools.js +69 -0
  12. package/dist/runtime/composables/useCobrasMode.d.ts +0 -0
  13. package/dist/runtime/composables/useCobrasMode.js +25 -0
  14. package/dist/runtime/middleware/auth.d.ts +0 -0
  15. package/dist/runtime/middleware/auth.js +36 -0
  16. package/dist/runtime/middleware/internal.d.ts +0 -0
  17. package/dist/runtime/middleware/internal.js +19 -0
  18. package/dist/runtime/plugins/auth.client.d.ts +0 -0
  19. package/dist/runtime/plugins/auth.client.js +122 -0
  20. package/dist/runtime/plugins/auth.server.d.ts +0 -0
  21. package/dist/runtime/plugins/auth.server.js +69 -0
  22. package/dist/runtime/server/api/exchange.post.d.ts +0 -0
  23. package/dist/runtime/server/api/exchange.post.js +49 -0
  24. package/dist/runtime/server/api/logout.post.d.ts +0 -0
  25. package/dist/runtime/server/api/logout.post.js +27 -0
  26. package/dist/runtime/server/api/refresh.post.d.ts +0 -0
  27. package/dist/runtime/server/api/refresh.post.js +24 -0
  28. package/dist/runtime/server/api/verify.get.d.ts +0 -0
  29. package/dist/runtime/server/api/verify.get.js +50 -0
  30. package/dist/types.d.mts +7 -0
  31. package/dist/types.d.ts +7 -0
  32. package/package.json +62 -0
@@ -0,0 +1,89 @@
1
+ <script setup lang="ts">
2
+ import { useCobrasAuth, useCobrasDevTools } from '#imports'
3
+
4
+ const { user, isAdmin } = useCobrasAuth()
5
+ const { state, isAvailable, toggle, close, setFeatureFlag, getFeatureFlag, toggleDebugMode } = useCobrasDevTools()
6
+
7
+ const featureFlagInput = ref('')
8
+
9
+ function addFeatureFlag() {
10
+ if (featureFlagInput.value.trim()) {
11
+ setFeatureFlag(featureFlagInput.value.trim(), true)
12
+ featureFlagInput.value = ''
13
+ }
14
+ }
15
+ </script>
16
+
17
+ <template>
18
+ <Teleport to="body">
19
+ <Transition name="slide">
20
+ <div
21
+ v-if="isAvailable && state.isOpen"
22
+ class="cobras-devtools"
23
+ >
24
+ <div class="cobras-devtools-header">
25
+ <span class="cobras-devtools-title">Cobras Dev Tools</span>
26
+ <button class="cobras-devtools-close" @click="close">&times;</button>
27
+ </div>
28
+
29
+ <div class="cobras-devtools-content">
30
+ <!-- User Info -->
31
+ <div class="cobras-devtools-section">
32
+ <h4>User</h4>
33
+ <div class="cobras-devtools-info">
34
+ <span>{{ user?.name || 'Unknown' }}</span>
35
+ <span class="cobras-devtools-badge">{{ user?.role }}</span>
36
+ </div>
37
+ <div class="cobras-devtools-email">{{ user?.email }}</div>
38
+ </div>
39
+
40
+ <!-- Debug Mode -->
41
+ <div class="cobras-devtools-section">
42
+ <h4>Debug</h4>
43
+ <label class="cobras-devtools-toggle">
44
+ <input
45
+ type="checkbox"
46
+ :checked="state.debugMode"
47
+ @change="toggleDebugMode"
48
+ />
49
+ <span>Debug Mode</span>
50
+ </label>
51
+ </div>
52
+
53
+ <!-- Feature Flags -->
54
+ <div class="cobras-devtools-section">
55
+ <h4>Feature Flags</h4>
56
+ <div class="cobras-devtools-flags">
57
+ <div
58
+ v-for="(enabled, key) in state.featureFlags"
59
+ :key="key"
60
+ class="cobras-devtools-flag"
61
+ >
62
+ <label>
63
+ <input
64
+ type="checkbox"
65
+ :checked="enabled"
66
+ @change="setFeatureFlag(String(key), !enabled)"
67
+ />
68
+ {{ key }}
69
+ </label>
70
+ </div>
71
+ </div>
72
+ <div class="cobras-devtools-add-flag">
73
+ <input
74
+ v-model="featureFlagInput"
75
+ placeholder="Add flag..."
76
+ @keyup.enter="addFeatureFlag"
77
+ />
78
+ <button @click="addFeatureFlag">+</button>
79
+ </div>
80
+ </div>
81
+ </div>
82
+ </div>
83
+ </Transition>
84
+ </Teleport>
85
+ </template>
86
+
87
+ <style scoped>
88
+ .cobras-devtools{background:#1a1a2e;border:1px solid #333;border-radius:8px;bottom:20px;box-shadow:0 4px 20px rgba(0,0,0,.5);color:#e0e0e0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:13px;position:fixed;right:20px;width:320px;z-index:99999}.cobras-devtools-header{align-items:center;background:#16213e;border-bottom:1px solid #333;border-radius:8px 8px 0 0;display:flex;justify-content:space-between;padding:12px 16px}.cobras-devtools-title{color:#fff;font-weight:600}.cobras-devtools-close{background:none;border:none;color:#888;cursor:pointer;font-size:20px;line-height:1;padding:0}.cobras-devtools-close:hover{color:#fff}.cobras-devtools-content{max-height:400px;overflow-y:auto;padding:16px}.cobras-devtools-section{margin-bottom:16px}.cobras-devtools-section:last-child{margin-bottom:0}.cobras-devtools-section h4{color:#888;font-size:11px;letter-spacing:.5px;margin:0 0 8px;text-transform:uppercase}.cobras-devtools-info{align-items:center;display:flex;gap:8px}.cobras-devtools-badge{background:#0f3460;border-radius:4px;font-size:11px;padding:2px 8px;text-transform:uppercase}.cobras-devtools-email{color:#888;font-size:12px;margin-top:4px}.cobras-devtools-toggle{align-items:center;cursor:pointer;display:flex;gap:8px}.cobras-devtools-toggle input{cursor:pointer}.cobras-devtools-flags{display:flex;flex-direction:column;gap:6px}.cobras-devtools-flag label{align-items:center;cursor:pointer;display:flex;gap:8px}.cobras-devtools-add-flag{display:flex;gap:8px;margin-top:8px}.cobras-devtools-add-flag input{background:#16213e;border:1px solid #333;border-radius:4px;color:#e0e0e0;flex:1;font-size:12px;padding:6px 10px}.cobras-devtools-add-flag button{background:#0f3460;border:none;border-radius:4px;color:#fff;cursor:pointer;padding:6px 12px}.cobras-devtools-add-flag button:hover{background:#1a4a7a}.slide-enter-active,.slide-leave-active{transition:all .2s ease}.slide-enter-from,.slide-leave-to{opacity:0;transform:translateY(20px)}
89
+ </style>
File without changes
@@ -0,0 +1,99 @@
1
+ import { useState, useRuntimeConfig, computed } from "#imports";
2
+ export function useCobrasAuth() {
3
+ const config = useRuntimeConfig();
4
+ const authConfig = config.public.cobrasAuth;
5
+ const state = useState("cobras-auth-state", () => ({
6
+ user: null,
7
+ initialized: false,
8
+ loading: false,
9
+ error: null
10
+ }));
11
+ const user = computed({
12
+ get: () => state.value.user,
13
+ set: (val) => {
14
+ state.value.user = val;
15
+ }
16
+ });
17
+ const isAuthenticated = computed(() => !!state.value.user);
18
+ const isInternalUser = computed(() => !!state.value.user);
19
+ const isAdmin = computed(() => state.value.user?.role === "admin");
20
+ async function checkAuth() {
21
+ if (state.value.loading) return;
22
+ state.value.loading = true;
23
+ state.value.error = null;
24
+ try {
25
+ const response = await $fetch("/api/_cobras/verify", {
26
+ credentials: "include"
27
+ });
28
+ if (response.valid && response.user) {
29
+ state.value.user = response.user;
30
+ } else {
31
+ state.value.user = null;
32
+ }
33
+ } catch (error) {
34
+ state.value.user = null;
35
+ state.value.error = error.message || "Auth check failed";
36
+ if (authConfig.debug) {
37
+ console.warn("[@cobras/auth-nuxt] Auth check failed:", error);
38
+ }
39
+ } finally {
40
+ state.value.loading = false;
41
+ state.value.initialized = true;
42
+ }
43
+ }
44
+ function login(redirect) {
45
+ const currentUrl = redirect || (typeof window !== "undefined" ? window.location.href : "/");
46
+ const loginUrl = `${authConfig.authServiceUrl}/login?redirect=${encodeURIComponent(currentUrl)}`;
47
+ if (typeof window !== "undefined") {
48
+ window.location.href = loginUrl;
49
+ }
50
+ }
51
+ async function logout() {
52
+ try {
53
+ await $fetch("/api/_cobras/logout", {
54
+ method: "POST",
55
+ credentials: "include"
56
+ });
57
+ } catch (error) {
58
+ if (authConfig.debug) {
59
+ console.warn("[@cobras/auth-nuxt] Logout error:", error);
60
+ }
61
+ }
62
+ state.value.user = null;
63
+ if (authConfig.mode === "internal" && typeof window !== "undefined") {
64
+ window.location.href = authConfig.authServiceUrl;
65
+ }
66
+ }
67
+ async function verifySiteAccess() {
68
+ if (!state.value.user) return false;
69
+ if (!authConfig.siteId && !authConfig.siteDomain) return true;
70
+ try {
71
+ const response = await $fetch(
72
+ `${authConfig.authServiceUrl}/api/auth/check-access`,
73
+ {
74
+ method: "POST",
75
+ body: {
76
+ siteId: authConfig.siteId,
77
+ siteDomain: authConfig.siteDomain
78
+ },
79
+ credentials: "include"
80
+ }
81
+ );
82
+ return response.hasAccess;
83
+ } catch {
84
+ return false;
85
+ }
86
+ }
87
+ return {
88
+ user,
89
+ state,
90
+ isAuthenticated,
91
+ isInternalUser,
92
+ isAdmin,
93
+ mode: authConfig.mode,
94
+ checkAuth,
95
+ login,
96
+ logout,
97
+ verifySiteAccess
98
+ };
99
+ }
@@ -0,0 +1,69 @@
1
+ import { useState, useRuntimeConfig, computed } from "#imports";
2
+ import { useCobrasAuth } from "./useCobrasAuth.js";
3
+ export function useCobrasDevTools() {
4
+ const config = useRuntimeConfig();
5
+ const authConfig = config.public.cobrasAuth;
6
+ const { isAuthenticated } = useCobrasAuth();
7
+ const state = useState("cobras-devtools-state", () => ({
8
+ isOpen: false,
9
+ featureFlags: {},
10
+ debugMode: false,
11
+ showMetrics: false
12
+ }));
13
+ const isAvailable = computed(() => {
14
+ return authConfig.enableDevTools && isAuthenticated.value;
15
+ });
16
+ function toggle() {
17
+ if (!isAvailable.value) return;
18
+ state.value.isOpen = !state.value.isOpen;
19
+ }
20
+ function open() {
21
+ if (!isAvailable.value) return;
22
+ state.value.isOpen = true;
23
+ }
24
+ function close() {
25
+ state.value.isOpen = false;
26
+ }
27
+ function setFeatureFlag(key, value) {
28
+ state.value.featureFlags[key] = value;
29
+ if (typeof window !== "undefined") {
30
+ localStorage.setItem("cobras-feature-flags", JSON.stringify(state.value.featureFlags));
31
+ }
32
+ }
33
+ function getFeatureFlag(key) {
34
+ return state.value.featureFlags[key] ?? false;
35
+ }
36
+ function toggleDebugMode() {
37
+ state.value.debugMode = !state.value.debugMode;
38
+ if (typeof window !== "undefined") {
39
+ localStorage.setItem("cobras-debug-mode", String(state.value.debugMode));
40
+ }
41
+ }
42
+ function toggleMetrics() {
43
+ state.value.showMetrics = !state.value.showMetrics;
44
+ }
45
+ if (typeof window !== "undefined") {
46
+ const savedFlags = localStorage.getItem("cobras-feature-flags");
47
+ if (savedFlags) {
48
+ try {
49
+ state.value.featureFlags = JSON.parse(savedFlags);
50
+ } catch {
51
+ }
52
+ }
53
+ const savedDebug = localStorage.getItem("cobras-debug-mode");
54
+ if (savedDebug) {
55
+ state.value.debugMode = savedDebug === "true";
56
+ }
57
+ }
58
+ return {
59
+ state,
60
+ isAvailable,
61
+ toggle,
62
+ open,
63
+ close,
64
+ setFeatureFlag,
65
+ getFeatureFlag,
66
+ toggleDebugMode,
67
+ toggleMetrics
68
+ };
69
+ }
File without changes
@@ -0,0 +1,25 @@
1
+ import { useRuntimeConfig, computed } from "#imports";
2
+ import { useCobrasAuth } from "./useCobrasAuth.js";
3
+ export function useCobrasMode() {
4
+ const config = useRuntimeConfig();
5
+ const authConfig = config.public.cobrasAuth;
6
+ const { isAuthenticated, isAdmin } = useCobrasAuth();
7
+ const mode = authConfig.mode;
8
+ const isInternalMode = mode === "internal";
9
+ const isPublicMode = mode === "public";
10
+ const showInternalFeatures = computed(() => isAuthenticated.value);
11
+ const showAdminFeatures = computed(() => isAdmin.value);
12
+ const devToolsEnabled = computed(() => {
13
+ if (!authConfig.enableDevTools) return false;
14
+ if (isPublicMode) return isAuthenticated.value;
15
+ return isAuthenticated.value;
16
+ });
17
+ return {
18
+ mode,
19
+ isInternalMode,
20
+ isPublicMode,
21
+ showInternalFeatures: showInternalFeatures.value,
22
+ showAdminFeatures: showAdminFeatures.value,
23
+ devToolsEnabled: devToolsEnabled.value
24
+ };
25
+ }
File without changes
@@ -0,0 +1,36 @@
1
+ import { defineNuxtRouteMiddleware, useRuntimeConfig, useState, navigateTo } from "#imports";
2
+ export default defineNuxtRouteMiddleware(async (to) => {
3
+ const config = useRuntimeConfig();
4
+ const authConfig = config.public.cobrasAuth;
5
+ const state = useState("cobras-auth-state");
6
+ if (to.query.code) {
7
+ return;
8
+ }
9
+ if (!state.value?.initialized) {
10
+ return;
11
+ }
12
+ if (authConfig.mode === "public") {
13
+ return;
14
+ }
15
+ const isPublicRoute = authConfig.publicRoutes.some((route) => {
16
+ if (route.endsWith("*")) {
17
+ return to.path.startsWith(route.slice(0, -1));
18
+ }
19
+ return to.path === route;
20
+ });
21
+ if (isPublicRoute) {
22
+ return;
23
+ }
24
+ if (!state.value?.user) {
25
+ let redirectUrl;
26
+ if (typeof window !== "undefined") {
27
+ redirectUrl = window.location.href;
28
+ } else {
29
+ redirectUrl = to.fullPath;
30
+ }
31
+ return navigateTo(
32
+ `${authConfig.authServiceUrl}/login?redirect_uri=${encodeURIComponent(redirectUrl)}`,
33
+ { external: true }
34
+ );
35
+ }
36
+ });
File without changes
@@ -0,0 +1,19 @@
1
+ import { defineNuxtRouteMiddleware, useRuntimeConfig, useState, navigateTo } from "#imports";
2
+ export default defineNuxtRouteMiddleware(async (to) => {
3
+ const config = useRuntimeConfig();
4
+ const authConfig = config.public.cobrasAuth;
5
+ const state = useState("cobras-auth-state");
6
+ if (to.query.code) {
7
+ return;
8
+ }
9
+ if (!state.value?.initialized) {
10
+ return;
11
+ }
12
+ if (!state.value?.user) {
13
+ const currentUrl = typeof window !== "undefined" ? window.location.href : to.fullPath;
14
+ return navigateTo(
15
+ `${authConfig.authServiceUrl}/login?redirect_uri=${encodeURIComponent(currentUrl)}`,
16
+ { external: true }
17
+ );
18
+ }
19
+ });
File without changes
@@ -0,0 +1,122 @@
1
+ import { defineNuxtPlugin, useRuntimeConfig, useState, computed, useRoute, useRouter } from "#imports";
2
+ export default defineNuxtPlugin(async (nuxtApp) => {
3
+ const config = useRuntimeConfig();
4
+ const authConfig = config.public.cobrasAuth;
5
+ const route = useRoute();
6
+ const router = useRouter();
7
+ const state = useState("cobras-auth-state", () => ({
8
+ user: null,
9
+ initialized: false,
10
+ loading: false,
11
+ error: null
12
+ }));
13
+ const user = computed(() => state.value.user);
14
+ const isAuthenticated = computed(() => !!state.value.user);
15
+ const isInternalUser = computed(() => !!state.value.user);
16
+ const isAdmin = computed(() => state.value.user?.role === "admin");
17
+ async function exchangeCode(code2) {
18
+ try {
19
+ const response = await $fetch("/api/_cobras/exchange", {
20
+ method: "POST",
21
+ body: { code: code2 },
22
+ credentials: "include"
23
+ });
24
+ if (response.success && response.user) {
25
+ state.value.user = response.user;
26
+ return true;
27
+ }
28
+ } catch (error) {
29
+ if (authConfig.debug) {
30
+ console.warn("[@cobras/auth-nuxt] Code exchange failed:", error);
31
+ }
32
+ }
33
+ return false;
34
+ }
35
+ async function checkAuth() {
36
+ if (state.value.loading) return;
37
+ state.value.loading = true;
38
+ state.value.error = null;
39
+ try {
40
+ const response = await $fetch("/api/_cobras/verify", {
41
+ credentials: "include"
42
+ });
43
+ if (response.valid && response.user) {
44
+ state.value.user = response.user;
45
+ } else {
46
+ state.value.user = null;
47
+ }
48
+ } catch (error) {
49
+ state.value.user = null;
50
+ if (error.statusCode !== 401 && authConfig.debug) {
51
+ console.warn("[@cobras/auth-nuxt] Auth check failed:", error);
52
+ }
53
+ } finally {
54
+ state.value.loading = false;
55
+ state.value.initialized = true;
56
+ }
57
+ }
58
+ function login(redirect) {
59
+ const currentUrl = redirect || window.location.href;
60
+ const loginUrl = `${authConfig.authServiceUrl}/login?redirect_uri=${encodeURIComponent(currentUrl)}`;
61
+ window.location.href = loginUrl;
62
+ }
63
+ async function logout() {
64
+ try {
65
+ await $fetch("/api/_cobras/logout", {
66
+ method: "POST",
67
+ credentials: "include"
68
+ });
69
+ } catch (error) {
70
+ if (authConfig.debug) {
71
+ console.warn("[@cobras/auth-nuxt] Logout error:", error);
72
+ }
73
+ }
74
+ state.value.user = null;
75
+ if (authConfig.mode === "internal") {
76
+ window.location.href = authConfig.authServiceUrl;
77
+ }
78
+ }
79
+ const code = route.query.code;
80
+ if (code) {
81
+ const success = await exchangeCode(code);
82
+ if (success) {
83
+ const newQuery = { ...route.query };
84
+ delete newQuery.code;
85
+ router.replace({ query: newQuery });
86
+ }
87
+ }
88
+ await checkAuth();
89
+ if (authConfig.enableDevTools && authConfig.devToolsKey) {
90
+ const keys = authConfig.devToolsKey.toLowerCase().split("+");
91
+ document.addEventListener("keydown", (e) => {
92
+ const pressed = [
93
+ e.ctrlKey && "ctrl",
94
+ e.shiftKey && "shift",
95
+ e.altKey && "alt",
96
+ e.metaKey && "meta",
97
+ e.key.toLowerCase()
98
+ ].filter(Boolean);
99
+ if (keys.every((k) => pressed.includes(k)) && isAuthenticated.value) {
100
+ const devToolsState = useState("cobras-devtools-state");
101
+ if (devToolsState.value) {
102
+ devToolsState.value.isOpen = !devToolsState.value.isOpen;
103
+ }
104
+ }
105
+ });
106
+ }
107
+ const cobrasAuth = {
108
+ user,
109
+ isAuthenticated,
110
+ isInternalUser,
111
+ isAdmin,
112
+ mode: authConfig.mode,
113
+ checkAuth,
114
+ login,
115
+ logout
116
+ };
117
+ return {
118
+ provide: {
119
+ cobrasAuth
120
+ }
121
+ };
122
+ });
File without changes
@@ -0,0 +1,69 @@
1
+ import { defineNuxtPlugin, useRuntimeConfig, useState, computed, useRequestHeaders } from "#imports";
2
+ export default defineNuxtPlugin(async (nuxtApp) => {
3
+ const config = useRuntimeConfig();
4
+ const authConfig = config.public.cobrasAuth;
5
+ const state = useState("cobras-auth-state", () => ({
6
+ user: null,
7
+ initialized: false,
8
+ loading: false,
9
+ error: null
10
+ }));
11
+ const user = computed(() => state.value.user);
12
+ const isAuthenticated = computed(() => !!state.value.user);
13
+ const isInternalUser = computed(() => !!state.value.user);
14
+ const isAdmin = computed(() => state.value.user?.role === "admin");
15
+ async function checkAuth() {
16
+ if (state.value.loading) return;
17
+ state.value.loading = true;
18
+ state.value.error = null;
19
+ try {
20
+ const headers = useRequestHeaders(["cookie"]);
21
+ const response = await $fetch(
22
+ `${authConfig.authServiceUrl}/api/auth/verify`,
23
+ {
24
+ headers: {
25
+ cookie: headers.cookie || ""
26
+ }
27
+ }
28
+ );
29
+ if (response.valid && response.user) {
30
+ state.value.user = response.user;
31
+ } else {
32
+ state.value.user = null;
33
+ }
34
+ } catch (error) {
35
+ state.value.user = null;
36
+ if (error.statusCode !== 401 && authConfig.debug) {
37
+ console.warn("[@cobras/auth-nuxt] SSR auth check failed:", error.message);
38
+ }
39
+ } finally {
40
+ state.value.loading = false;
41
+ state.value.initialized = true;
42
+ }
43
+ }
44
+ function login(redirect) {
45
+ }
46
+ async function logout() {
47
+ state.value.user = null;
48
+ }
49
+ const cobrasAuth = {
50
+ user,
51
+ isAuthenticated,
52
+ isInternalUser,
53
+ isAdmin,
54
+ mode: authConfig.mode,
55
+ checkAuth,
56
+ login,
57
+ logout
58
+ };
59
+ if (authConfig.mode === "internal") {
60
+ await checkAuth();
61
+ } else {
62
+ state.value.initialized = true;
63
+ }
64
+ return {
65
+ provide: {
66
+ cobrasAuth
67
+ }
68
+ };
69
+ });
File without changes
@@ -0,0 +1,49 @@
1
+ import { defineEventHandler, readBody, createError, setCookie } from "h3";
2
+ import { useRuntimeConfig } from "#imports";
3
+ export default defineEventHandler(async (event) => {
4
+ const config = useRuntimeConfig();
5
+ const authServiceUrl = config.public.cobrasAuth.authServiceUrl;
6
+ const body = await readBody(event);
7
+ const { code } = body;
8
+ if (!code) {
9
+ throw createError({
10
+ statusCode: 400,
11
+ message: "code is required"
12
+ });
13
+ }
14
+ try {
15
+ const response = await $fetch(`${authServiceUrl}/api/auth/token`, {
16
+ method: "POST",
17
+ body: { code }
18
+ });
19
+ if (!response.success || !response.user) {
20
+ throw createError({
21
+ statusCode: 401,
22
+ message: "Invalid code"
23
+ });
24
+ }
25
+ const session = {
26
+ user: response.user,
27
+ expires_at: response.expires_at
28
+ };
29
+ const sessionData = Buffer.from(JSON.stringify(session)).toString("base64");
30
+ setCookie(event, "cobras_session", sessionData, {
31
+ httpOnly: true,
32
+ secure: process.env.NODE_ENV === "production",
33
+ sameSite: "lax",
34
+ path: "/",
35
+ maxAge: 24 * 60 * 60
36
+ // 24 hours
37
+ });
38
+ return {
39
+ success: true,
40
+ user: response.user
41
+ };
42
+ } catch (error) {
43
+ console.error("[@cobras/auth-nuxt] Code exchange failed:", error.message);
44
+ throw createError({
45
+ statusCode: error.statusCode || 500,
46
+ message: error.message || "Code exchange failed"
47
+ });
48
+ }
49
+ });
File without changes
@@ -0,0 +1,27 @@
1
+ import { defineEventHandler, getHeader, setCookie } from "h3";
2
+ import { useRuntimeConfig } from "#imports";
3
+ export default defineEventHandler(async (event) => {
4
+ const config = useRuntimeConfig();
5
+ const authServiceUrl = config.public.cobrasAuth.authServiceUrl;
6
+ const cookieDomain = config.cobrasAuth?.cookieDomain;
7
+ const cookieHeader = getHeader(event, "cookie") || "";
8
+ try {
9
+ await $fetch(`${authServiceUrl}/api/auth/logout`, {
10
+ method: "POST",
11
+ headers: {
12
+ cookie: cookieHeader
13
+ }
14
+ });
15
+ } catch {
16
+ }
17
+ const cookieOptions = {
18
+ httpOnly: true,
19
+ secure: true,
20
+ sameSite: "lax",
21
+ path: "/",
22
+ ...cookieDomain ? { domain: cookieDomain } : {}
23
+ };
24
+ setCookie(event, "access_token", "", { ...cookieOptions, maxAge: 0 });
25
+ setCookie(event, "refresh_token", "", { ...cookieOptions, maxAge: 0 });
26
+ return { success: true };
27
+ });
File without changes
@@ -0,0 +1,24 @@
1
+ import { defineEventHandler, getHeader, createError } from "h3";
2
+ import { useRuntimeConfig } from "#imports";
3
+ export default defineEventHandler(async (event) => {
4
+ const config = useRuntimeConfig();
5
+ const authServiceUrl = config.public.cobrasAuth.authServiceUrl;
6
+ const cookieHeader = getHeader(event, "cookie") || "";
7
+ try {
8
+ const response = await $fetch(
9
+ `${authServiceUrl}/api/auth/refresh`,
10
+ {
11
+ method: "POST",
12
+ headers: {
13
+ cookie: cookieHeader
14
+ }
15
+ }
16
+ );
17
+ return response;
18
+ } catch (error) {
19
+ throw createError({
20
+ statusCode: error.statusCode || 500,
21
+ message: error.message || "Token refresh failed"
22
+ });
23
+ }
24
+ });
File without changes