@thunderid/nuxt 0.0.1

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 (116) hide show
  1. package/LICENSE +201 -0
  2. package/dist/module.d.mts +46 -0
  3. package/dist/module.json +9 -0
  4. package/dist/module.mjs +216 -0
  5. package/dist/runtime/components/ThunderIDRoot.d.ts +52 -0
  6. package/dist/runtime/components/ThunderIDRoot.js +160 -0
  7. package/dist/runtime/components/actions/SignInButton.d.ts +37 -0
  8. package/dist/runtime/components/actions/SignInButton.js +51 -0
  9. package/dist/runtime/components/actions/SignOutButton.d.ts +34 -0
  10. package/dist/runtime/components/actions/SignOutButton.js +43 -0
  11. package/dist/runtime/components/actions/SignUpButton.d.ts +33 -0
  12. package/dist/runtime/components/actions/SignUpButton.js +48 -0
  13. package/dist/runtime/components/auth/Callback.d.ts +43 -0
  14. package/dist/runtime/components/auth/Callback.js +93 -0
  15. package/dist/runtime/components/auth/SignIn.d.ts +38 -0
  16. package/dist/runtime/components/auth/SignIn.js +60 -0
  17. package/dist/runtime/components/auth/SignUp.d.ts +40 -0
  18. package/dist/runtime/components/auth/SignUp.js +79 -0
  19. package/dist/runtime/components/control/Loading.d.ts +36 -0
  20. package/dist/runtime/components/control/Loading.js +17 -0
  21. package/dist/runtime/components/control/SignedIn.d.ts +38 -0
  22. package/dist/runtime/components/control/SignedIn.js +17 -0
  23. package/dist/runtime/components/control/SignedOut.d.ts +37 -0
  24. package/dist/runtime/components/control/SignedOut.js +17 -0
  25. package/dist/runtime/components/organization/CreateOrganization.d.ts +32 -0
  26. package/dist/runtime/components/organization/CreateOrganization.js +29 -0
  27. package/dist/runtime/components/organization/Organization.d.ts +39 -0
  28. package/dist/runtime/components/organization/Organization.js +17 -0
  29. package/dist/runtime/components/organization/OrganizationList.d.ts +34 -0
  30. package/dist/runtime/components/organization/OrganizationList.js +30 -0
  31. package/dist/runtime/components/organization/OrganizationProfile.d.ts +32 -0
  32. package/dist/runtime/components/organization/OrganizationProfile.js +32 -0
  33. package/dist/runtime/components/organization/OrganizationSwitcher.d.ts +36 -0
  34. package/dist/runtime/components/organization/OrganizationSwitcher.js +26 -0
  35. package/dist/runtime/components/user/User.d.ts +38 -0
  36. package/dist/runtime/components/user/User.js +17 -0
  37. package/dist/runtime/components/user/UserDropdown.d.ts +38 -0
  38. package/dist/runtime/components/user/UserDropdown.js +45 -0
  39. package/dist/runtime/components/user/UserProfile.d.ts +35 -0
  40. package/dist/runtime/components/user/UserProfile.js +35 -0
  41. package/dist/runtime/composables/useThunderID.d.ts +38 -0
  42. package/dist/runtime/composables/useThunderID.js +73 -0
  43. package/dist/runtime/errors/error-codes.d.ts +40 -0
  44. package/dist/runtime/errors/error-codes.js +19 -0
  45. package/dist/runtime/errors/index.d.ts +19 -0
  46. package/dist/runtime/errors/index.js +2 -0
  47. package/dist/runtime/errors/thunderid-error.d.ts +47 -0
  48. package/dist/runtime/errors/thunderid-error.js +15 -0
  49. package/dist/runtime/middleware/auth.d.ts +35 -0
  50. package/dist/runtime/middleware/auth.js +2 -0
  51. package/dist/runtime/middleware/defineThunderIDMiddleware.d.ts +53 -0
  52. package/dist/runtime/middleware/defineThunderIDMiddleware.js +24 -0
  53. package/dist/runtime/plugins/thunderid.d.ts +39 -0
  54. package/dist/runtime/plugins/thunderid.js +128 -0
  55. package/dist/runtime/server/ThunderIDNuxtClient.d.ts +186 -0
  56. package/dist/runtime/server/ThunderIDNuxtClient.js +384 -0
  57. package/dist/runtime/server/index.d.ts +33 -0
  58. package/dist/runtime/server/index.js +3 -0
  59. package/dist/runtime/server/plugins/thunderid-ssr.d.ts +40 -0
  60. package/dist/runtime/server/plugins/thunderid-ssr.js +135 -0
  61. package/dist/runtime/server/routes/auth/branding/branding.get.d.ts +31 -0
  62. package/dist/runtime/server/routes/auth/branding/branding.get.js +40 -0
  63. package/dist/runtime/server/routes/auth/organizations/current.get.d.ts +29 -0
  64. package/dist/runtime/server/routes/auth/organizations/current.get.js +24 -0
  65. package/dist/runtime/server/routes/auth/organizations/id.get.d.ts +28 -0
  66. package/dist/runtime/server/routes/auth/organizations/id.get.js +28 -0
  67. package/dist/runtime/server/routes/auth/organizations/index.get.d.ts +28 -0
  68. package/dist/runtime/server/routes/auth/organizations/index.get.js +24 -0
  69. package/dist/runtime/server/routes/auth/organizations/index.post.d.ts +30 -0
  70. package/dist/runtime/server/routes/auth/organizations/index.post.js +30 -0
  71. package/dist/runtime/server/routes/auth/organizations/me.get.d.ts +28 -0
  72. package/dist/runtime/server/routes/auth/organizations/me.get.js +24 -0
  73. package/dist/runtime/server/routes/auth/organizations/switch.post.d.ts +32 -0
  74. package/dist/runtime/server/routes/auth/organizations/switch.post.js +49 -0
  75. package/dist/runtime/server/routes/auth/session/callback.get.d.ts +27 -0
  76. package/dist/runtime/server/routes/auth/session/callback.get.js +91 -0
  77. package/dist/runtime/server/routes/auth/session/callback.post.d.ts +48 -0
  78. package/dist/runtime/server/routes/auth/session/callback.post.js +53 -0
  79. package/dist/runtime/server/routes/auth/session/session.get.d.ts +26 -0
  80. package/dist/runtime/server/routes/auth/session/session.get.js +22 -0
  81. package/dist/runtime/server/routes/auth/session/signin.get.d.ts +29 -0
  82. package/dist/runtime/server/routes/auth/session/signin.get.js +37 -0
  83. package/dist/runtime/server/routes/auth/session/signin.post.d.ts +37 -0
  84. package/dist/runtime/server/routes/auth/session/signin.post.js +102 -0
  85. package/dist/runtime/server/routes/auth/session/signout.post.d.ts +31 -0
  86. package/dist/runtime/server/routes/auth/session/signout.post.js +38 -0
  87. package/dist/runtime/server/routes/auth/session/signup.post.d.ts +36 -0
  88. package/dist/runtime/server/routes/auth/session/signup.post.js +30 -0
  89. package/dist/runtime/server/routes/auth/session/token.get.d.ts +29 -0
  90. package/dist/runtime/server/routes/auth/session/token.get.js +6 -0
  91. package/dist/runtime/server/routes/auth/user/profile.get.d.ts +29 -0
  92. package/dist/runtime/server/routes/auth/user/profile.get.js +24 -0
  93. package/dist/runtime/server/routes/auth/user/profile.patch.d.ts +35 -0
  94. package/dist/runtime/server/routes/auth/user/profile.patch.js +41 -0
  95. package/dist/runtime/server/routes/auth/user/user.get.d.ts +25 -0
  96. package/dist/runtime/server/routes/auth/user/user.get.js +21 -0
  97. package/dist/runtime/server/utils/event-context.d.ts +49 -0
  98. package/dist/runtime/server/utils/event-context.js +3 -0
  99. package/dist/runtime/server/utils/serverSession.d.ts +65 -0
  100. package/dist/runtime/server/utils/serverSession.js +44 -0
  101. package/dist/runtime/server/utils/session.d.ts +85 -0
  102. package/dist/runtime/server/utils/session.js +106 -0
  103. package/dist/runtime/server/utils/token-refresh.d.ts +42 -0
  104. package/dist/runtime/server/utils/token-refresh.js +65 -0
  105. package/dist/runtime/types.d.ts +161 -0
  106. package/dist/runtime/types.js +0 -0
  107. package/dist/runtime/utils/createRouteMatcher.d.ts +40 -0
  108. package/dist/runtime/utils/createRouteMatcher.js +7 -0
  109. package/dist/runtime/utils/index.d.ts +30 -0
  110. package/dist/runtime/utils/index.js +1 -0
  111. package/dist/runtime/utils/log.d.ts +44 -0
  112. package/dist/runtime/utils/log.js +25 -0
  113. package/dist/runtime/utils/url-validation.d.ts +49 -0
  114. package/dist/runtime/utils/url-validation.js +38 -0
  115. package/dist/types.d.mts +7 -0
  116. package/package.json +101 -0
@@ -0,0 +1,160 @@
1
+ import { generateFlattenedUserProfile } from "@thunderid/browser";
2
+ import {
3
+ BrandingProvider,
4
+ FlowMetaProvider,
5
+ FlowProvider,
6
+ I18nProvider,
7
+ OrganizationProvider,
8
+ ThemeProvider,
9
+ UserProvider
10
+ } from "@thunderid/vue";
11
+ import { defineComponent, h } from "vue";
12
+ import { useState, useRuntimeConfig } from "#imports";
13
+ const ThunderIDRoot = defineComponent({
14
+ name: "ThunderIDRoot",
15
+ setup(_props, { slots }) {
16
+ const userProfileState = useState("thunderid:user-profile");
17
+ const currentOrgState = useState("thunderid:current-org");
18
+ const myOrgsState = useState("thunderid:my-orgs");
19
+ const brandingState = useState("thunderid:branding");
20
+ const authState = useState("thunderid:auth");
21
+ const prefs = useRuntimeConfig().public.thunderid?.preferences;
22
+ const shouldFetchProfile = prefs?.user?.fetchUserProfile !== false;
23
+ const shouldFetchOrgs = prefs?.user?.fetchOrganizations !== false;
24
+ const shouldFetchBranding = prefs?.theme?.inheritFromBranding !== false;
25
+ const themeMode = prefs?.theme?.mode ?? "light";
26
+ const onUpdateProfile = (payload) => {
27
+ const prev = userProfileState.value;
28
+ userProfileState.value = prev ? {
29
+ ...prev,
30
+ flattenedProfile: generateFlattenedUserProfile(payload, prev.schemas),
31
+ profile: payload
32
+ } : {
33
+ flattenedProfile: generateFlattenedUserProfile(payload, []),
34
+ profile: payload,
35
+ schemas: []
36
+ };
37
+ authState.value = { ...authState.value, user: payload };
38
+ };
39
+ const updateProfile = async (requestConfig, _sessionId) => {
40
+ if (_sessionId) {
41
+ }
42
+ try {
43
+ const result = await $fetch("/api/auth/user/profile", {
44
+ body: requestConfig,
45
+ method: "PATCH"
46
+ });
47
+ if (result?.success && result.data?.user) {
48
+ onUpdateProfile(result.data.user);
49
+ }
50
+ return result;
51
+ } catch (err) {
52
+ return { data: { user: {} }, error: String(err), success: false };
53
+ }
54
+ };
55
+ const revalidateProfile = async () => {
56
+ try {
57
+ const res = await $fetch("/api/auth/user/profile");
58
+ if (res) userProfileState.value = res;
59
+ } catch {
60
+ }
61
+ };
62
+ const onOrganizationSwitch = async (organization) => $fetch("/api/auth/organizations/switch", { body: { organization }, method: "POST" });
63
+ const getAllOrganizations = async () => $fetch("/api/auth/organizations");
64
+ const revalidateMyOrganizations = async () => {
65
+ try {
66
+ const res = await $fetch("/api/auth/organizations/me");
67
+ myOrgsState.value = res ?? [];
68
+ return myOrgsState.value;
69
+ } catch {
70
+ return myOrgsState.value;
71
+ }
72
+ };
73
+ const createOrganization = async (payload) => $fetch("/api/auth/organizations", { body: payload, method: "POST" });
74
+ const revalidateCurrentOrganization = async () => {
75
+ try {
76
+ const res = await $fetch("/api/auth/organizations/current");
77
+ currentOrgState.value = res ?? null;
78
+ return currentOrgState.value;
79
+ } catch {
80
+ return currentOrgState.value;
81
+ }
82
+ };
83
+ const revalidateBranding = async () => {
84
+ try {
85
+ const res = await $fetch("/api/auth/branding");
86
+ if (res) brandingState.value = res;
87
+ } catch {
88
+ }
89
+ };
90
+ return () => h(
91
+ I18nProvider,
92
+ { preferences: prefs?.i18n },
93
+ {
94
+ default: () => h(
95
+ FlowMetaProvider,
96
+ { enabled: false },
97
+ {
98
+ default: () => h(
99
+ BrandingProvider,
100
+ {
101
+ // When inheritFromBranding is disabled, pass null so the provider
102
+ // falls back to its own default theme without using SSR-fetched data.
103
+ brandingPreference: shouldFetchBranding ? brandingState.value : null,
104
+ revalidateBranding: shouldFetchBranding ? revalidateBranding : void 0
105
+ },
106
+ {
107
+ default: () => h(
108
+ ThemeProvider,
109
+ {
110
+ // Mirror the same flag used in the Nitro plugin gate.
111
+ inheritFromBranding: shouldFetchBranding,
112
+ mode: themeMode
113
+ },
114
+ {
115
+ default: () => h(FlowProvider, null, {
116
+ default: () => h(
117
+ UserProvider,
118
+ {
119
+ // When fetchUserProfile is false the Nitro plugin
120
+ // skips SCIM calls, so we must also pass empty values
121
+ // here to keep SSR and client in sync.
122
+ flattenedProfile: shouldFetchProfile ? userProfileState.value?.flattenedProfile ?? null : null,
123
+ onUpdateProfile: shouldFetchProfile ? onUpdateProfile : void 0,
124
+ profile: shouldFetchProfile ? userProfileState.value : null,
125
+ revalidateProfile: shouldFetchProfile ? revalidateProfile : void 0,
126
+ schemas: shouldFetchProfile ? userProfileState.value?.schemas ?? null : null,
127
+ updateProfile: shouldFetchProfile ? updateProfile : void 0
128
+ },
129
+ {
130
+ default: () => h(
131
+ OrganizationProvider,
132
+ {
133
+ // When fetchOrganizations is false pass empty
134
+ // values so the provider renders without org data.
135
+ createOrganization: shouldFetchOrgs ? createOrganization : void 0,
136
+ currentOrganization: shouldFetchOrgs ? currentOrgState.value : null,
137
+ getAllOrganizations: shouldFetchOrgs ? getAllOrganizations : void 0,
138
+ myOrganizations: shouldFetchOrgs ? myOrgsState.value : [],
139
+ onOrganizationSwitch: shouldFetchOrgs ? onOrganizationSwitch : void 0,
140
+ revalidateCurrentOrganization: shouldFetchOrgs ? revalidateCurrentOrganization : void 0,
141
+ revalidateMyOrganizations: shouldFetchOrgs ? revalidateMyOrganizations : void 0
142
+ },
143
+ {
144
+ default: () => slots["default"]?.()
145
+ }
146
+ )
147
+ }
148
+ )
149
+ })
150
+ }
151
+ )
152
+ }
153
+ )
154
+ }
155
+ )
156
+ }
157
+ );
158
+ }
159
+ });
160
+ export default ThunderIDRoot;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
3
+ *
4
+ * WSO2 LLC. licenses this file to you under the Apache License,
5
+ * Version 2.0 (the "License"); you may not use this file except
6
+ * in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing,
12
+ * software distributed under the License is distributed on an
13
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ * KIND, either express or implied. See the License for the
15
+ * specific language governing permissions and limitations
16
+ * under the License.
17
+ */
18
+ import { type Component } from 'vue';
19
+ /**
20
+ * Nuxt-specific SignInButton container.
21
+ *
22
+ * Mirrors the Next.js SDK's SignInButton: imports {@link BaseSignInButton} from
23
+ * `@thunderid/vue` and wires navigation through Nuxt's `navigateTo` so
24
+ * server-side redirects work correctly (no `window.location` access).
25
+ *
26
+ * The `signIn` action and `signInUrl` come from the Nuxt-specific
27
+ * {@link useThunderID} composable which is provided via the Nuxt auto-import
28
+ * layer — not directly from `@thunderid/vue`.
29
+ *
30
+ * @example
31
+ * ```vue
32
+ * <ThunderIDSignInButton />
33
+ * <ThunderIDSignInButton class="btn-primary">Log in</ThunderIDSignInButton>
34
+ * ```
35
+ */
36
+ declare const SignInButton: Component;
37
+ export default SignInButton;
@@ -0,0 +1,51 @@
1
+ import { ThunderIDRuntimeError } from "@thunderid/browser";
2
+ import { BaseSignInButton } from "@thunderid/vue";
3
+ import { defineComponent, h, ref } from "vue";
4
+ import { navigateTo } from "#app";
5
+ import { useThunderID } from "#imports";
6
+ const SignInButton = defineComponent({
7
+ emits: ["click", "error"],
8
+ name: "SignInButton",
9
+ props: {
10
+ signInOptions: { default: void 0, type: Object }
11
+ },
12
+ setup(props, { slots, emit, attrs }) {
13
+ const { signIn, signInUrl, signInOptions: contextSignInOptions } = useThunderID();
14
+ const isLoading = ref(false);
15
+ const handleSignIn = async (e) => {
16
+ try {
17
+ isLoading.value = true;
18
+ if (signInUrl) {
19
+ await navigateTo(signInUrl, { external: true });
20
+ } else {
21
+ await signIn(props.signInOptions ?? contextSignInOptions);
22
+ }
23
+ if (e) emit("click", e);
24
+ } catch (error) {
25
+ emit("error", error);
26
+ throw new ThunderIDRuntimeError(
27
+ `Sign in failed: ${error instanceof Error ? error.message : String(error)}`,
28
+ "SignInButton-handleSignIn-RuntimeError-001",
29
+ "nuxt",
30
+ "Something went wrong while trying to sign in. Please try again later."
31
+ );
32
+ } finally {
33
+ isLoading.value = false;
34
+ }
35
+ };
36
+ return () => {
37
+ const slotContent = slots["default"] ? () => slots["default"]({ isLoading: isLoading.value }) : void 0;
38
+ return h(
39
+ BaseSignInButton,
40
+ {
41
+ class: attrs["class"],
42
+ isLoading: isLoading.value,
43
+ onClick: handleSignIn,
44
+ style: attrs["style"]
45
+ },
46
+ slotContent
47
+ );
48
+ };
49
+ }
50
+ });
51
+ export default SignInButton;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
3
+ *
4
+ * WSO2 LLC. licenses this file to you under the Apache License,
5
+ * Version 2.0 (the "License"); you may not use this file except
6
+ * in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing,
12
+ * software distributed under the License is distributed on an
13
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ * KIND, either express or implied. See the License for the
15
+ * specific language governing permissions and limitations
16
+ * under the License.
17
+ */
18
+ import { type Component } from 'vue';
19
+ /**
20
+ * Nuxt-specific SignOutButton container.
21
+ *
22
+ * Imports {@link BaseSignOutButton} from `@thunderid/vue` and wires the
23
+ * `signOut` action through the Nuxt-specific {@link useThunderID} composable
24
+ * (auto-import layer), which uses Nuxt's `navigateTo` instead of
25
+ * `window.location`.
26
+ *
27
+ * @example
28
+ * ```vue
29
+ * <ThunderIDSignOutButton />
30
+ * <ThunderIDSignOutButton class="btn-secondary">Sign out</ThunderIDSignOutButton>
31
+ * ```
32
+ */
33
+ declare const SignOutButton: Component;
34
+ export default SignOutButton;
@@ -0,0 +1,43 @@
1
+ import { ThunderIDRuntimeError } from "@thunderid/browser";
2
+ import { BaseSignOutButton } from "@thunderid/vue";
3
+ import { defineComponent, h, ref } from "vue";
4
+ import { useThunderID } from "#imports";
5
+ const SignOutButton = defineComponent({
6
+ emits: ["click", "error"],
7
+ name: "SignOutButton",
8
+ setup(_, { slots, emit, attrs }) {
9
+ const { signOut } = useThunderID();
10
+ const isLoading = ref(false);
11
+ const handleSignOut = async (e) => {
12
+ try {
13
+ isLoading.value = true;
14
+ await signOut();
15
+ if (e) emit("click", e);
16
+ } catch (error) {
17
+ emit("error", error);
18
+ throw new ThunderIDRuntimeError(
19
+ `Sign out failed: ${error instanceof Error ? error.message : String(error)}`,
20
+ "SignOutButton-handleSignOut-RuntimeError-001",
21
+ "nuxt",
22
+ "Something went wrong while trying to sign out. Please try again later."
23
+ );
24
+ } finally {
25
+ isLoading.value = false;
26
+ }
27
+ };
28
+ return () => {
29
+ const slotContent = slots["default"] ? () => slots["default"]({ isLoading: isLoading.value }) : void 0;
30
+ return h(
31
+ BaseSignOutButton,
32
+ {
33
+ class: attrs["class"],
34
+ isLoading: isLoading.value,
35
+ onClick: handleSignOut,
36
+ style: attrs["style"]
37
+ },
38
+ slotContent
39
+ );
40
+ };
41
+ }
42
+ });
43
+ export default SignOutButton;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
3
+ *
4
+ * WSO2 LLC. licenses this file to you under the Apache License,
5
+ * Version 2.0 (the "License"); you may not use this file except
6
+ * in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing,
12
+ * software distributed under the License is distributed on an
13
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ * KIND, either express or implied. See the License for the
15
+ * specific language governing permissions and limitations
16
+ * under the License.
17
+ */
18
+ import { type Component } from 'vue';
19
+ /**
20
+ * Nuxt-specific SignUpButton container.
21
+ *
22
+ * Imports {@link BaseSignUpButton} from `@thunderid/vue` and wires navigation
23
+ * through Nuxt's `navigateTo` so a configured `signUpUrl` is followed
24
+ * SSR-safely instead of via `window.location`.
25
+ *
26
+ * @example
27
+ * ```vue
28
+ * <ThunderIDSignUpButton />
29
+ * <ThunderIDSignUpButton class="btn-primary">Create account</ThunderIDSignUpButton>
30
+ * ```
31
+ */
32
+ declare const SignUpButton: Component;
33
+ export default SignUpButton;
@@ -0,0 +1,48 @@
1
+ import { ThunderIDRuntimeError } from "@thunderid/browser";
2
+ import { BaseSignUpButton } from "@thunderid/vue";
3
+ import { defineComponent, h, ref } from "vue";
4
+ import { navigateTo } from "#app";
5
+ import { useThunderID } from "#imports";
6
+ const SignUpButton = defineComponent({
7
+ emits: ["click", "error"],
8
+ name: "SignUpButton",
9
+ setup(_, { slots, emit, attrs }) {
10
+ const { signUp, signUpUrl } = useThunderID();
11
+ const isLoading = ref(false);
12
+ const handleSignUp = async (e) => {
13
+ try {
14
+ isLoading.value = true;
15
+ if (signUpUrl) {
16
+ await navigateTo(signUpUrl, { external: true });
17
+ } else {
18
+ await signUp();
19
+ }
20
+ if (e) emit("click", e);
21
+ } catch (error) {
22
+ emit("error", error);
23
+ throw new ThunderIDRuntimeError(
24
+ `Sign up failed: ${error instanceof Error ? error.message : String(error)}`,
25
+ "SignUpButton-handleSignUp-RuntimeError-001",
26
+ "nuxt",
27
+ "Something went wrong while trying to sign up. Please try again later."
28
+ );
29
+ } finally {
30
+ isLoading.value = false;
31
+ }
32
+ };
33
+ return () => {
34
+ const slotContent = slots["default"] ? () => slots["default"]({ isLoading: isLoading.value }) : void 0;
35
+ return h(
36
+ BaseSignUpButton,
37
+ {
38
+ class: attrs["class"],
39
+ isLoading: isLoading.value,
40
+ onClick: handleSignUp,
41
+ style: attrs["style"]
42
+ },
43
+ slotContent
44
+ );
45
+ };
46
+ }
47
+ });
48
+ export default SignUpButton;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
3
+ *
4
+ * WSO2 LLC. licenses this file to you under the Apache License,
5
+ * Version 2.0 (the "License"); you may not use this file except
6
+ * in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing,
12
+ * software distributed under the License is distributed on an
13
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ * KIND, either express or implied. See the License for the
15
+ * specific language governing permissions and limitations
16
+ * under the License.
17
+ */
18
+ import { type Component } from 'vue';
19
+ /**
20
+ * Nuxt-specific Callback component.
21
+ *
22
+ * Handles OAuth callback parameter forwarding — extracts `code`, `state`, and
23
+ * `error` from the URL, validates the state stored in `sessionStorage`, and
24
+ * forwards the OAuth parameters to the originating route.
25
+ *
26
+ * **SSR-safe**: all `window` / `sessionStorage` access is gated inside
27
+ * `onMounted`, which only runs on the client. Navigation uses Nuxt's
28
+ * `navigateTo` instead of `window.location` so the redirect is handled
29
+ * correctly in both SSR and CSR contexts.
30
+ *
31
+ * Pass `onNavigate` to override the navigation handler (e.g. for testing or
32
+ * custom routing logic).
33
+ *
34
+ * @example
35
+ * ```vue
36
+ * <!-- pages/callback.vue -->
37
+ * <template>
38
+ * <ThunderIDCallback :on-error="handleError" />
39
+ * </template>
40
+ * ```
41
+ */
42
+ declare const Callback: Component;
43
+ export default Callback;
@@ -0,0 +1,93 @@
1
+ import { defineComponent, onMounted } from "vue";
2
+ import { navigateTo } from "#app";
3
+ const error = (msg, ...args) => {
4
+ console.error(`[@thunderid/nuxt] Callback: ${msg}`, ...args);
5
+ };
6
+ const Callback = defineComponent({
7
+ name: "Callback",
8
+ props: {
9
+ onError: { default: void 0, type: Function },
10
+ onNavigate: { default: void 0, type: Function }
11
+ },
12
+ setup(props) {
13
+ const navigate = (path) => {
14
+ if (props.onNavigate) {
15
+ props.onNavigate(path);
16
+ } else {
17
+ navigateTo(path);
18
+ }
19
+ };
20
+ onMounted(() => {
21
+ let returnPath = "/";
22
+ try {
23
+ const urlParams = new URLSearchParams(window.location.search);
24
+ const code = urlParams.get("code");
25
+ const state = urlParams.get("state");
26
+ const nonce = urlParams.get("nonce");
27
+ const oauthError = urlParams.get("error");
28
+ const errorDescription = urlParams.get("error_description");
29
+ if (!code && !state && !oauthError) {
30
+ return;
31
+ }
32
+ if (!state) {
33
+ throw new Error("Missing OAuth state parameter - possible security issue");
34
+ }
35
+ const storedData = sessionStorage.getItem(`thunderid_oauth_${state}`);
36
+ if (!storedData) {
37
+ if (oauthError) {
38
+ const errorMsg = errorDescription || oauthError || "OAuth authentication failed";
39
+ const err = new Error(errorMsg);
40
+ props.onError?.(err);
41
+ const params2 = new URLSearchParams();
42
+ params2.set("error", oauthError);
43
+ if (errorDescription) {
44
+ params2.set("error_description", errorDescription);
45
+ }
46
+ navigate(`/?${params2.toString()}`);
47
+ return;
48
+ }
49
+ throw new Error("Invalid OAuth state - possible CSRF attack");
50
+ }
51
+ const { path, timestamp } = JSON.parse(storedData);
52
+ returnPath = path || "/";
53
+ const MAX_STATE_AGE = 3e5;
54
+ if (Date.now() - timestamp > MAX_STATE_AGE) {
55
+ sessionStorage.removeItem(`thunderid_oauth_${state}`);
56
+ throw new Error("OAuth state expired - please try again");
57
+ }
58
+ sessionStorage.removeItem(`thunderid_oauth_${state}`);
59
+ if (oauthError) {
60
+ const errorMsg = errorDescription || oauthError || "OAuth authentication failed";
61
+ const err = new Error(errorMsg);
62
+ props.onError?.(err);
63
+ const params2 = new URLSearchParams();
64
+ params2.set("error", oauthError);
65
+ if (errorDescription) {
66
+ params2.set("error_description", errorDescription);
67
+ }
68
+ navigate(`${returnPath}?${params2.toString()}`);
69
+ return;
70
+ }
71
+ if (!code) {
72
+ throw new Error("Missing OAuth authorization code");
73
+ }
74
+ const params = new URLSearchParams();
75
+ params.set("code", code);
76
+ if (nonce) {
77
+ params.set("nonce", nonce);
78
+ }
79
+ navigate(`${returnPath}?${params.toString()}`);
80
+ } catch (err) {
81
+ const errorMessage = err instanceof Error ? err.message : "OAuth callback processing failed";
82
+ error("OAuth callback error:", err);
83
+ props.onError?.(err instanceof Error ? err : new Error(errorMessage));
84
+ const params = new URLSearchParams();
85
+ params.set("error", "callback_error");
86
+ params.set("error_description", errorMessage);
87
+ navigate(`${returnPath}?${params.toString()}`);
88
+ }
89
+ });
90
+ return () => null;
91
+ }
92
+ });
93
+ export default Callback;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com).
3
+ *
4
+ * WSO2 LLC. licenses this file to you under the Apache License,
5
+ * Version 2.0 (the "License"); you may not use this file except
6
+ * in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing,
12
+ * software distributed under the License is distributed on an
13
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ * KIND, either express or implied. See the License for the
15
+ * specific language governing permissions and limitations
16
+ * under the License.
17
+ */
18
+ import { type Component } from 'vue';
19
+ /**
20
+ * Nuxt-specific SignIn container for the embedded (app-native) sign-in flow.
21
+ *
22
+ * Mirrors the Vue SDK's `SignIn` container but replaces all `window.location`
23
+ * navigation with Nuxt's `navigateTo` so redirects after a successful embedded
24
+ * sign-in are SSR-safe.
25
+ *
26
+ * Uses `useThunderID()` from the Nuxt auto-import layer — the Nuxt-specific
27
+ * wrapper that provides Nitro-route-aware `signIn`, `signOut`, `signUp`.
28
+ *
29
+ * Delegates all UI rendering to {@link BaseSignIn} from `@thunderid/vue`, which
30
+ * itself is platform-aware (routes to V1 authenticator or V2 component flow).
31
+ *
32
+ * @example
33
+ * ```vue
34
+ * <ThunderIDSignIn @success="onSignIn" @error="onError" />
35
+ * ```
36
+ */
37
+ declare const SignIn: Component;
38
+ export default SignIn;
@@ -0,0 +1,60 @@
1
+ import { BaseSignIn } from "@thunderid/vue";
2
+ import { defineComponent, h } from "vue";
3
+ import { navigateTo } from "#app";
4
+ import { useThunderID } from "#imports";
5
+ const SignIn = defineComponent({
6
+ emits: ["error", "success"],
7
+ name: "SignIn",
8
+ props: {
9
+ className: { default: "", type: String },
10
+ size: {
11
+ default: "medium",
12
+ type: String
13
+ },
14
+ variant: {
15
+ default: "outlined",
16
+ type: String
17
+ }
18
+ },
19
+ setup(props, { emit, attrs }) {
20
+ const { signIn, afterSignInUrl, isInitialized, isLoading } = useThunderID();
21
+ const handleInitialize = async () => (
22
+ // Pass flowId='' to trigger the embedded-flow initiation path in useThunderID.
23
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
24
+ await signIn({ flowId: "" }, {})
25
+ );
26
+ const handleOnSubmit = async (payload, request) => await signIn(payload, request);
27
+ const handleSuccess = async (authData) => {
28
+ emit("success", authData);
29
+ if (authData && afterSignInUrl) {
30
+ if (import.meta.client) {
31
+ const url = new URL(afterSignInUrl, window.location.origin);
32
+ Object.entries(authData).forEach(([key, value]) => {
33
+ if (value !== void 0 && value !== null) {
34
+ url.searchParams.append(key, String(value));
35
+ }
36
+ });
37
+ await navigateTo(url.pathname + url.search + url.hash);
38
+ } else {
39
+ await navigateTo(afterSignInUrl);
40
+ }
41
+ }
42
+ };
43
+ return () => h(BaseSignIn, {
44
+ ...attrs,
45
+ afterSignInUrl,
46
+ class: props.className,
47
+ isLoading: (isLoading?.value ?? false) || !(isInitialized?.value ?? true),
48
+ onError: (err) => emit("error", err),
49
+ onInitialize: handleInitialize,
50
+ onSubmit: handleOnSubmit,
51
+ onSuccess: handleSuccess,
52
+ showLogo: true,
53
+ showSubtitle: true,
54
+ showTitle: true,
55
+ size: props.size,
56
+ variant: props.variant
57
+ });
58
+ }
59
+ });
60
+ export default SignIn;