@arch-cadre/auth-google 1.0.6 → 1.0.8
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.
- package/dist/actions/auth.cjs +1 -1
- package/dist/actions/auth.mjs +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.mjs +3 -3
- package/dist/routes.cjs +2 -2
- package/dist/routes.mjs +2 -2
- package/dist/ui/google-button.cjs +3 -3
- package/dist/ui/google-button.mjs +2 -2
- package/dist/ui/settings-page.cjs +3 -3
- package/dist/ui/settings-page.mjs +2 -2
- package/package.json +9 -8
- package/src/actions/auth.ts +48 -0
- package/src/actions/settings.ts +31 -0
- package/src/index.ts +34 -0
- package/src/intl.d.ts +9 -0
- package/src/navigation.ts +15 -0
- package/src/routes.ts +105 -0
- package/src/ui/google-button.tsx +33 -0
- package/src/ui/settings-page.tsx +118 -0
package/dist/actions/auth.cjs
CHANGED
|
@@ -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.
|
|
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) {
|
package/dist/actions/auth.mjs
CHANGED
|
@@ -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.
|
|
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.
|
|
9
|
-
var _routes = require("./routes.
|
|
10
|
-
var _googleButton = require("./ui/google-button.
|
|
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.
|
|
3
|
-
import { apiRoutes, privateRoutes } from "./routes.
|
|
4
|
-
import { GoogleLoginButton } from "./ui/google-button.
|
|
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.
|
|
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.
|
|
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.
|
|
14
|
-
const GoogleAuthSettingsPage = dynamic(() => import("./ui/settings-page.
|
|
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);
|
|
@@ -5,16 +5,16 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
7
|
exports.GoogleLoginButton = GoogleLoginButton;
|
|
8
|
-
var
|
|
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.
|
|
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() {
|
|
15
15
|
const {
|
|
16
16
|
t
|
|
17
|
-
} = (0,
|
|
17
|
+
} = (0, _intl.useTranslation)();
|
|
18
18
|
return /* @__PURE__ */React.createElement(_ui.Button, {
|
|
19
19
|
type: "button",
|
|
20
20
|
variant: "outline",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useTranslation } from "@arch-cadre/intl
|
|
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.
|
|
5
|
+
import { loginWithGoogle } from "../actions/auth.js";
|
|
6
6
|
export function GoogleLoginButton() {
|
|
7
7
|
const { t } = useTranslation();
|
|
8
8
|
return /* @__PURE__ */ React.createElement(
|
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
7
|
module.exports = GoogleAuthSettingsPage;
|
|
8
|
-
var
|
|
8
|
+
var _intl = require("@arch-cadre/intl");
|
|
9
9
|
var _button = require("@arch-cadre/ui/components/button");
|
|
10
10
|
var _card = require("@arch-cadre/ui/components/card");
|
|
11
11
|
var _input = require("@arch-cadre/ui/components/input");
|
|
@@ -13,13 +13,13 @@ 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.
|
|
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() {
|
|
20
20
|
const {
|
|
21
21
|
t
|
|
22
|
-
} = (0,
|
|
22
|
+
} = (0, _intl.useTranslation)();
|
|
23
23
|
const [config, setConfig] = (0, _react.useState)({
|
|
24
24
|
clientId: "",
|
|
25
25
|
clientSecret: "",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useTranslation } from "@arch-cadre/intl
|
|
2
|
+
import { useTranslation } from "@arch-cadre/intl";
|
|
3
3
|
import { Button } from "@arch-cadre/ui/components/button";
|
|
4
4
|
import {
|
|
5
5
|
Card,
|
|
@@ -16,7 +16,7 @@ import { toast } from "sonner";
|
|
|
16
16
|
import {
|
|
17
17
|
getGoogleConfig,
|
|
18
18
|
updateGoogleConfig
|
|
19
|
-
} from "../actions/settings.
|
|
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.
|
|
3
|
+
"version": "1.0.8",
|
|
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.
|
|
29
|
+
"@arch-cadre/modules": "^0.0.78",
|
|
29
30
|
"@hookform/resolvers": "^3.10.0",
|
|
30
|
-
"@arch-cadre/ui": "^0.0.
|
|
31
|
+
"@arch-cadre/ui": "^0.0.52",
|
|
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.
|
|
39
|
-
"@arch-cadre/intl": "^0.0.
|
|
39
|
+
"@arch-cadre/core": "^0.0.52",
|
|
40
|
+
"@arch-cadre/intl": "^0.0.52",
|
|
40
41
|
"@types/react": "^19",
|
|
41
42
|
"next": "16.1.1",
|
|
42
43
|
"react": "^19.0.0",
|
|
@@ -44,9 +45,9 @@
|
|
|
44
45
|
"unbuild": "^3.6.1"
|
|
45
46
|
},
|
|
46
47
|
"peerDependencies": {
|
|
47
|
-
"@arch-cadre/core": "^0.0.
|
|
48
|
-
"@arch-cadre/ui": "^0.0.
|
|
49
|
-
"next": ">=
|
|
48
|
+
"@arch-cadre/core": "^0.0.52",
|
|
49
|
+
"@arch-cadre/ui": "^0.0.52",
|
|
50
|
+
"next": ">=15.0.0",
|
|
50
51
|
"react": "^19.0.0"
|
|
51
52
|
},
|
|
52
53
|
"main": "./dist/index.mjs"
|
|
@@ -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,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
|
+
}
|