@arch-cadre/auth-google 1.0.7 → 1.0.9

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.
@@ -8,7 +8,7 @@ exports.loginWithGoogle = loginWithGoogle;
8
8
  var _arctic = require("arctic");
9
9
  var _headers = require("next/headers");
10
10
  var _navigation = require("next/navigation");
11
- var _settings = require("./settings.cjs");
11
+ var _settings = require("./settings.js");
12
12
  async function loginWithGoogle() {
13
13
  const config = await (0, _settings.getGoogleConfig)();
14
14
  if (!config.clientId || !config.clientSecret) {
@@ -2,7 +2,7 @@
2
2
  import { Google, generateCodeVerifier, generateState } from "arctic";
3
3
  import { cookies } from "next/headers";
4
4
  import { redirect } from "next/navigation";
5
- import { getGoogleConfig } from "./settings.mjs";
5
+ import { getGoogleConfig } from "./settings.js";
6
6
  export async function loginWithGoogle() {
7
7
  const config = await getGoogleConfig();
8
8
  if (!config.clientId || !config.clientSecret) {
package/dist/index.cjs CHANGED
@@ -5,9 +5,9 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
 
7
7
  var _manifest = _interopRequireDefault(require("../manifest.json"));
8
- var _navigation = require("./navigation.cjs");
9
- var _routes = require("./routes.cjs");
10
- var _googleButton = require("./ui/google-button.cjs");
8
+ var _navigation = require("./navigation.js");
9
+ var _routes = require("./routes.js");
10
+ var _googleButton = require("./ui/google-button.js");
11
11
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
12
  const googleAuthModule = {
13
13
  manifest: _manifest.default,
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import manifest from "../manifest.json";
2
- import { navigation } from "./navigation.mjs";
3
- import { apiRoutes, privateRoutes } from "./routes.mjs";
4
- import { GoogleLoginButton } from "./ui/google-button.mjs";
2
+ import { navigation } from "./navigation.js";
3
+ import { apiRoutes, privateRoutes } from "./routes.js";
4
+ import { GoogleLoginButton } from "./ui/google-button.js";
5
5
  const googleAuthModule = {
6
6
  manifest,
7
7
  routes: {
package/dist/routes.cjs CHANGED
@@ -9,9 +9,9 @@ var _server = require("@arch-cadre/core/server");
9
9
  var _arctic = require("arctic");
10
10
  var _dynamic = _interopRequireDefault(require("next/dynamic"));
11
11
  var _headers = require("next/headers");
12
- var _settings = require("./actions/settings.cjs");
12
+ var _settings = require("./actions/settings.js");
13
13
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
- const GoogleAuthSettingsPage = (0, _dynamic.default)(() => Promise.resolve().then(() => require("./ui/settings-page.cjs")));
14
+ const GoogleAuthSettingsPage = (0, _dynamic.default)(() => Promise.resolve().then(() => require("./ui/settings-page.js")));
15
15
  async function getGoogleClient() {
16
16
  const config = await (0, _settings.getGoogleConfig)();
17
17
  return new _arctic.Google(config.clientId, config.clientSecret, config.redirectUri);
package/dist/routes.mjs CHANGED
@@ -10,8 +10,8 @@ import {
10
10
  import { decodeIdToken, Google } from "arctic";
11
11
  import dynamic from "next/dynamic";
12
12
  import { cookies } from "next/headers";
13
- import { getGoogleConfig } from "./actions/settings.mjs";
14
- const GoogleAuthSettingsPage = dynamic(() => import("./ui/settings-page.mjs"));
13
+ import { getGoogleConfig } from "./actions/settings.js";
14
+ const GoogleAuthSettingsPage = dynamic(() => import("./ui/settings-page.js"));
15
15
  async function getGoogleClient() {
16
16
  const config = await getGoogleConfig();
17
17
  return new Google(config.clientId, config.clientSecret, config.redirectUri);
@@ -8,7 +8,7 @@ exports.GoogleLoginButton = GoogleLoginButton;
8
8
  var _intl = require("@arch-cadre/intl");
9
9
  var _ui = require("@arch-cadre/ui");
10
10
  var React = _interopRequireWildcard(require("react"));
11
- var _auth = require("../actions/auth.cjs");
11
+ var _auth = require("../actions/auth.js");
12
12
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
13
13
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
14
14
  function GoogleLoginButton() {
@@ -2,7 +2,7 @@
2
2
  import { useTranslation } from "@arch-cadre/intl";
3
3
  import { Button } from "@arch-cadre/ui";
4
4
  import * as React from "react";
5
- import { loginWithGoogle } from "../actions/auth.mjs";
5
+ import { loginWithGoogle } from "../actions/auth.js";
6
6
  export function GoogleLoginButton() {
7
7
  const { t } = useTranslation();
8
8
  return /* @__PURE__ */ React.createElement(
@@ -13,7 +13,7 @@ var _label = require("@arch-cadre/ui/components/label");
13
13
  var _react = _interopRequireWildcard(require("react"));
14
14
  var React = _react;
15
15
  var _sonner = require("sonner");
16
- var _settings = require("../actions/settings.cjs");
16
+ var _settings = require("../actions/settings.js");
17
17
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
18
18
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
19
19
  function GoogleAuthSettingsPage() {
@@ -16,7 +16,7 @@ import { toast } from "sonner";
16
16
  import {
17
17
  getGoogleConfig,
18
18
  updateGoogleConfig
19
- } from "../actions/settings.mjs";
19
+ } from "../actions/settings.js";
20
20
  export default function GoogleAuthSettingsPage() {
21
21
  const { t } = useTranslation();
22
22
  const [config, setConfig] = useState({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arch-cadre/auth-google",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "Google Auth module for Kryo framework",
5
5
  "type": "module",
6
6
  "exports": {
@@ -13,6 +13,7 @@
13
13
  },
14
14
  "files": [
15
15
  "dist",
16
+ "src",
16
17
  "locales",
17
18
  "manifest.json"
18
19
  ],
@@ -25,9 +26,9 @@
25
26
  "build": "unbuild"
26
27
  },
27
28
  "dependencies": {
28
- "@arch-cadre/modules": "^0.0.73",
29
+ "@arch-cadre/modules": "^0.0.79",
29
30
  "@hookform/resolvers": "^3.10.0",
30
- "@arch-cadre/ui": "^0.0.47",
31
+ "@arch-cadre/ui": "^0.0.53",
31
32
  "arctic": "^3.7.0",
32
33
  "lucide-react": "^0.475.0",
33
34
  "react-hook-form": "^7.54.2",
@@ -35,8 +36,8 @@
35
36
  "zod": "^3.24.1"
36
37
  },
37
38
  "devDependencies": {
38
- "@arch-cadre/core": "^0.0.47",
39
- "@arch-cadre/intl": "^0.0.47",
39
+ "@arch-cadre/core": "^0.0.53",
40
+ "@arch-cadre/intl": "^0.0.53",
40
41
  "@types/react": "^19",
41
42
  "next": "16.1.1",
42
43
  "react": "^19.0.0",
@@ -44,8 +45,8 @@
44
45
  "unbuild": "^3.6.1"
45
46
  },
46
47
  "peerDependencies": {
47
- "@arch-cadre/core": "^0.0.47",
48
- "@arch-cadre/ui": "^0.0.47",
48
+ "@arch-cadre/core": "^0.0.53",
49
+ "@arch-cadre/ui": "^0.0.53",
49
50
  "next": ">=15.0.0",
50
51
  "react": "^19.0.0"
51
52
  },
@@ -0,0 +1,48 @@
1
+ "use server";
2
+
3
+ import { Google, generateCodeVerifier, generateState } from "arctic";
4
+ import { cookies } from "next/headers";
5
+ import { redirect } from "next/navigation";
6
+ import { getGoogleConfig } from "./settings.js";
7
+
8
+ export async function loginWithGoogle() {
9
+ const config = await getGoogleConfig();
10
+
11
+ if (!config.clientId || !config.clientSecret) {
12
+ throw new Error("Google Auth is not configured. Please visit settings.");
13
+ }
14
+
15
+ const google = new Google(
16
+ config.clientId,
17
+ config.clientSecret,
18
+ config.redirectUri,
19
+ );
20
+ const state = generateState();
21
+ const codeVerifier = generateCodeVerifier();
22
+
23
+ const url = google.createAuthorizationURL(state, codeVerifier, [
24
+ "openid",
25
+ "profile",
26
+ "email",
27
+ ]);
28
+
29
+ const cookieStore = await cookies();
30
+
31
+ cookieStore.set("google_oauth_state", state, {
32
+ path: "/",
33
+ secure: process.env.NODE_ENV === "production",
34
+ httpOnly: true,
35
+ maxAge: 60 * 10,
36
+ sameSite: "lax",
37
+ });
38
+
39
+ cookieStore.set("google_code_verifier", codeVerifier, {
40
+ path: "/",
41
+ secure: process.env.NODE_ENV === "production",
42
+ httpOnly: true,
43
+ maxAge: 60 * 10,
44
+ sameSite: "lax",
45
+ });
46
+
47
+ return redirect(url.toString());
48
+ }
@@ -0,0 +1,31 @@
1
+ "use server";
2
+
3
+ import {
4
+ getKryoPathPrefix,
5
+ getModuleConfig,
6
+ updateModuleConfig,
7
+ } from "@arch-cadre/modules/server";
8
+ import { revalidatePath } from "next/cache";
9
+
10
+ export interface GoogleAuthConfig {
11
+ clientId: string;
12
+ clientSecret: string;
13
+ redirectUri: string;
14
+ }
15
+
16
+ export async function getGoogleConfig() {
17
+ const config = await getModuleConfig<GoogleAuthConfig>("google-auth");
18
+ return (
19
+ config ?? {
20
+ clientId: "",
21
+ clientSecret: "",
22
+ redirectUri: "http://localhost:3000/api/auth/google/callback",
23
+ }
24
+ );
25
+ }
26
+
27
+ export async function updateGoogleConfig(config: GoogleAuthConfig) {
28
+ await updateModuleConfig("google-auth", config);
29
+ revalidatePath(`${getKryoPathPrefix()}/google-auth/settings`);
30
+ return { success: true };
31
+ }
package/src/index.ts ADDED
@@ -0,0 +1,34 @@
1
+ import type { IModule } from "@arch-cadre/modules";
2
+ import manifest from "../manifest.json";
3
+ import { navigation } from "./navigation.js";
4
+ import { apiRoutes, privateRoutes } from "./routes.js";
5
+ import { GoogleLoginButton } from "./ui/google-button.js";
6
+
7
+ const googleAuthModule: IModule = {
8
+ manifest,
9
+
10
+ routes: {
11
+ private: privateRoutes,
12
+ api: apiRoutes,
13
+ },
14
+
15
+ extensions: [
16
+ {
17
+ id: "google-login-signin",
18
+ targetModule: "auth",
19
+ point: "signin:extra-buttons",
20
+ component: GoogleLoginButton,
21
+ priority: 10,
22
+ },
23
+ {
24
+ id: "google-login-signup",
25
+ targetModule: "auth",
26
+ point: "signup:extra-buttons",
27
+ component: GoogleLoginButton,
28
+ priority: 10,
29
+ },
30
+ ],
31
+ navigation,
32
+ };
33
+
34
+ export default googleAuthModule;
package/src/intl.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import type messages from "../locales/en/global.json";
2
+
3
+ type JsonDataType = typeof messages;
4
+
5
+ declare module "@arch-cadre/intl" {
6
+ export interface IntlMessages extends JsonDataType {}
7
+ }
8
+
9
+ export {};
@@ -0,0 +1,15 @@
1
+ import { i18n } from "@arch-cadre/intl";
2
+ import type { ModuleNavigation } from "@arch-cadre/modules";
3
+
4
+ export const navigation: ModuleNavigation = {
5
+ admin: {
6
+ [i18n("Security")]: [
7
+ {
8
+ id: "google-auth-settings",
9
+ title: i18n("Google Auth"),
10
+ url: "/google-auth/settings",
11
+ icon: "solar:lock-keyhole-bold-duotone",
12
+ },
13
+ ],
14
+ },
15
+ };
package/src/routes.ts ADDED
@@ -0,0 +1,105 @@
1
+ import { eventBus } from "@arch-cadre/core";
2
+ import {
3
+ createOAuthUser,
4
+ createSession,
5
+ generateSessionToken,
6
+ getUserFromEmail,
7
+ performFullUserAugmentation,
8
+ setSessionTokenCookie,
9
+ } from "@arch-cadre/core/server";
10
+ import type {
11
+ ApiRouteDefinition,
12
+ PrivateRouteDefinition,
13
+ } from "@arch-cadre/modules";
14
+ import { decodeIdToken, Google } from "arctic";
15
+ import dynamic from "next/dynamic";
16
+ import { cookies } from "next/headers";
17
+ import { getGoogleConfig } from "./actions/settings.js";
18
+
19
+ const GoogleAuthSettingsPage = dynamic(() => import("./ui/settings-page.js"));
20
+
21
+ async function getGoogleClient() {
22
+ const config = await getGoogleConfig();
23
+ return new Google(config.clientId, config.clientSecret, config.redirectUri);
24
+ }
25
+
26
+ export const privateRoutes: PrivateRouteDefinition[] = [
27
+ {
28
+ path: "/google-auth/settings", // Będzie widoczne pod /module/google-auth/settings
29
+ component: GoogleAuthSettingsPage,
30
+ auth: true,
31
+ },
32
+ ];
33
+
34
+ export const apiRoutes: ApiRouteDefinition[] = [
35
+ {
36
+ path: "/api/auth/google/callback",
37
+ handler: async (request: Request) => {
38
+ const google = await getGoogleClient();
39
+ const url = new URL(request.url);
40
+ const code = url.searchParams.get("code");
41
+ const state = url.searchParams.get("state");
42
+
43
+ const cookieStore = await cookies();
44
+ const storedState = cookieStore.get("google_oauth_state")?.value;
45
+ const codeVerifier = cookieStore.get("google_code_verifier")?.value;
46
+
47
+ if (
48
+ !code ||
49
+ !state ||
50
+ !storedState ||
51
+ !codeVerifier ||
52
+ state !== storedState
53
+ ) {
54
+ return new Response("Invalid state or code", { status: 400 });
55
+ }
56
+
57
+ try {
58
+ const tokens = await google.validateAuthorizationCode(
59
+ code,
60
+ codeVerifier,
61
+ );
62
+ const idToken = tokens.idToken();
63
+ const claims = decodeIdToken(idToken) as {
64
+ email: string;
65
+ name: string;
66
+ picture?: string;
67
+ };
68
+
69
+ let user = await getUserFromEmail(claims.email);
70
+
71
+ if (!user) {
72
+ user = await createOAuthUser(
73
+ claims.email,
74
+ claims.name,
75
+ claims.picture,
76
+ );
77
+ }
78
+
79
+ const sessionToken = await generateSessionToken();
80
+ const session = await createSession(sessionToken, user.id, {});
81
+ await setSessionTokenCookie(sessionToken, session.expiresAt);
82
+
83
+ const fullUser = await performFullUserAugmentation(user);
84
+ await eventBus.publish("auth:login", {
85
+ email: user.email,
86
+ userId: user.id,
87
+ });
88
+ await eventBus.publish("auth:session-created", {
89
+ session,
90
+ user: fullUser,
91
+ });
92
+
93
+ return new Response(null, {
94
+ status: 302,
95
+ headers: {
96
+ Location: "/",
97
+ },
98
+ });
99
+ } catch (error) {
100
+ console.error("[GoogleAuth] Error during callback:", error);
101
+ return new Response("Authentication failed", { status: 500 });
102
+ }
103
+ },
104
+ },
105
+ ];
@@ -0,0 +1,33 @@
1
+ "use client";
2
+ import { useTranslation } from "@arch-cadre/intl";
3
+
4
+ import { Button } from "@arch-cadre/ui";
5
+ import * as React from "react";
6
+ import { loginWithGoogle } from "../actions/auth.js";
7
+
8
+ export function GoogleLoginButton() {
9
+ const { t } = useTranslation();
10
+
11
+ return (
12
+ <Button
13
+ type="button"
14
+ variant="outline"
15
+ className="w-full gap-2"
16
+ onClick={() => loginWithGoogle()}
17
+ >
18
+ <svg
19
+ xmlns="http://www.w3.org/2000/svg"
20
+ viewBox="0 0 24 24"
21
+ className="size-4"
22
+ >
23
+ <title>{t("Continue with Google")}</title>
24
+ <path
25
+ d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"
26
+ fill="currentColor"
27
+ />
28
+ </svg>
29
+
30
+ {t("Continue with Google")}
31
+ </Button>
32
+ );
33
+ }
@@ -0,0 +1,118 @@
1
+ "use client";
2
+ import { useTranslation } from "@arch-cadre/intl";
3
+ import { Button } from "@arch-cadre/ui/components/button";
4
+ import {
5
+ Card,
6
+ CardContent,
7
+ CardDescription,
8
+ CardHeader,
9
+ CardTitle,
10
+ } from "@arch-cadre/ui/components/card";
11
+ import { Input } from "@arch-cadre/ui/components/input";
12
+ import { Label } from "@arch-cadre/ui/components/label";
13
+ import * as React from "react";
14
+ import { useEffect, useState } from "react";
15
+ import { toast } from "sonner";
16
+ import {
17
+ type GoogleAuthConfig,
18
+ getGoogleConfig,
19
+ updateGoogleConfig,
20
+ } from "../actions/settings.js";
21
+
22
+ export default function GoogleAuthSettingsPage() {
23
+ const { t } = useTranslation();
24
+
25
+ const [config, setConfig] = useState<GoogleAuthConfig>({
26
+ clientId: "",
27
+ clientSecret: "",
28
+ redirectUri: "",
29
+ });
30
+ const [loading, setLoading] = useState(true);
31
+
32
+ useEffect(() => {
33
+ getGoogleConfig().then((data) => {
34
+ setConfig(data);
35
+ setLoading(false);
36
+ });
37
+ }, []);
38
+
39
+ const handleSave = async (e: React.FormEvent) => {
40
+ e.preventDefault();
41
+ try {
42
+ await updateGoogleConfig(config);
43
+ toast.success(t("Settings saved successfully"));
44
+ } catch {
45
+ toast.error(
46
+ t(
47
+ "Failed to save settings. Please check your configuration and try again.",
48
+ ),
49
+ );
50
+ }
51
+ };
52
+
53
+ if (loading) return <div>{t("Google Auth")}</div>;
54
+
55
+ return (
56
+ <div className="container mx-auto py-10 max-w-2xl">
57
+ <Card>
58
+ <CardHeader>
59
+ <div>{t("Google Auth")}</div>
60
+ <div>{t("")}</div>
61
+
62
+ <CardTitle>{t("Google Authentication Settings")}</CardTitle>
63
+ <CardDescription>
64
+ {t(
65
+ "Configure your Google OAuth2 credentials. You can find these in the Google Cloud Console.",
66
+ )}
67
+ </CardDescription>
68
+ </CardHeader>
69
+ <CardContent>
70
+ <form onSubmit={handleSave} className="space-y-4">
71
+ <div className="space-y-2">
72
+ <Label htmlFor="clientId">{t("Client ID")}</Label>
73
+ <Input
74
+ id="clientId"
75
+ value={config.clientId}
76
+ onChange={(e) =>
77
+ setConfig({ ...config, clientId: e.target.value })
78
+ }
79
+ placeholder="xxx.apps.googleusercontent.com"
80
+ />
81
+ </div>
82
+ <div className="space-y-2">
83
+ <Label htmlFor="clientSecret">{t("Client Secret")}</Label>
84
+ <Input
85
+ id="clientSecret"
86
+ type="password"
87
+ value={config.clientSecret}
88
+ onChange={(e) =>
89
+ setConfig({ ...config, clientSecret: e.target.value })
90
+ }
91
+ placeholder="••••••••"
92
+ />
93
+ </div>
94
+ <div className="space-y-2">
95
+ <Label htmlFor="redirectUri">{t("Redirect URI")}</Label>
96
+ <Input
97
+ id="redirectUri"
98
+ value={config.redirectUri}
99
+ onChange={(e) =>
100
+ setConfig({ ...config, redirectUri: e.target.value })
101
+ }
102
+ placeholder="http://localhost:3000/api/auth/google/callback"
103
+ />
104
+ <p className="text-[10px] text-muted-foreground italic">
105
+ {t(
106
+ "Must match exactly with Google Cloud Console configuration.",
107
+ )}
108
+ </p>
109
+ </div>
110
+ <Button type="submit" className="w-full">
111
+ {t("Save Configuration")}
112
+ </Button>
113
+ </form>
114
+ </CardContent>
115
+ </Card>
116
+ </div>
117
+ );
118
+ }