mirror of
https://github.com/PeterMaquiran/tvone.git
synced 2026-04-23 12:35:51 +00:00
login to next backend
This commit is contained in:
@@ -10,7 +10,7 @@ import {
|
|||||||
// Importe o componente que criámos (ajuste o caminho se necessário)
|
// Importe o componente que criámos (ajuste o caminho se necessário)
|
||||||
import MultiAspectEditor from '../../components/MultiAspectEditor';
|
import MultiAspectEditor from '../../components/MultiAspectEditor';
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import { keycloak } from '@/app/feature/auth/keycloak-config';
|
// import { keycloak } from '@/app/feature/auth/keycloak-config';
|
||||||
const Editor = dynamic(
|
const Editor = dynamic(
|
||||||
() => import("@tinymce/tinymce-react").then((mod) => mod.Editor),
|
() => import("@tinymce/tinymce-react").then((mod) => mod.Editor),
|
||||||
{ ssr: false }
|
{ ssr: false }
|
||||||
@@ -100,36 +100,43 @@ const CreateNewsPage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Avoid hydration mismatch by waiting for mount
|
// Avoid hydration mismatch by waiting for mount
|
||||||
useEffect(() => {
|
// useEffect(() => {
|
||||||
keycloak.init({
|
// keycloak.init({
|
||||||
onLoad: "check-sso",
|
// onLoad: "check-sso",
|
||||||
pkceMethod: "S256",
|
// pkceMethod: "S256",
|
||||||
}).then(async (authenticated) => {
|
// }).then(async (authenticated) => {
|
||||||
if (authenticated) {
|
// if (authenticated) {
|
||||||
const token = keycloak.token!;
|
// const token = keycloak.token!;
|
||||||
localStorage.setItem("token", token);
|
// localStorage.setItem("token", token);
|
||||||
|
|
||||||
const res = await fetch("http://localhost:3001/profile/", {
|
// // 👉 send token to Next.js backend
|
||||||
headers: {
|
// fetch("/api/session", {
|
||||||
Authorization: `Bearer ${token}`,
|
// method: "POST",
|
||||||
},
|
// body: JSON.stringify({ token }),
|
||||||
});
|
// });
|
||||||
|
|
||||||
const profile = await res.json();
|
|
||||||
|
|
||||||
var keycloakData : {
|
// const res = await fetch("http://localhost:3001/profile/", {
|
||||||
email: string,
|
// headers: {
|
||||||
email_verified: boolean,
|
// //Authorization: `Bearer ${token}`,
|
||||||
name: string,
|
// },
|
||||||
picture: string,
|
// });
|
||||||
roles: string[]
|
|
||||||
} = profile.keycloak
|
|
||||||
|
|
||||||
setUser(keycloakData);
|
// const profile = await res.json();
|
||||||
console.log("Profile:", keycloakData);
|
|
||||||
}
|
// var keycloakData : {
|
||||||
});
|
// email: string,
|
||||||
}, []);
|
// email_verified: boolean,
|
||||||
|
// name: string,
|
||||||
|
// picture: string,
|
||||||
|
// roles: string[]
|
||||||
|
// } = profile.keycloak
|
||||||
|
|
||||||
|
// setUser(keycloakData);
|
||||||
|
// console.log("Profile:", keycloakData);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen bg-slate-100/50 text-slate-900 font-sans">
|
<div className="flex h-screen bg-slate-100/50 text-slate-900 font-sans">
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import React, { useState, useEffect } from "react";
|
|||||||
import { useGoogleLogin } from "@react-oauth/google";
|
import { useGoogleLogin } from "@react-oauth/google";
|
||||||
import { useTheme } from 'next-themes';
|
import { useTheme } from 'next-themes';
|
||||||
import { Sun, Moon } from 'lucide-react'; // Optional: install lucide-react for clean icons
|
import { Sun, Moon } from 'lucide-react'; // Optional: install lucide-react for clean icons
|
||||||
import { keycloak } from '@/app/feature/auth/keycloak-config';
|
//import { keycloak } from '@/app/feature/auth/keycloak-config';
|
||||||
|
|
||||||
interface GoogleAuthResponse {
|
interface GoogleAuthResponse {
|
||||||
access_token: string;
|
access_token: string;
|
||||||
@@ -33,27 +33,6 @@ export default function AppleStyleAuth() {
|
|||||||
const { theme, setTheme } = useTheme();
|
const { theme, setTheme } = useTheme();
|
||||||
const [mounted, setMounted] = useState(false);
|
const [mounted, setMounted] = useState(false);
|
||||||
|
|
||||||
// Avoid hydration mismatch by waiting for mount
|
|
||||||
useEffect(() => {
|
|
||||||
keycloak.init({
|
|
||||||
onLoad: "check-sso", // or "login-required"
|
|
||||||
pkceMethod: "S256",
|
|
||||||
}).then((authenticated) => {
|
|
||||||
if (authenticated) {
|
|
||||||
localStorage.setItem("token", keycloak.token!);
|
|
||||||
console.log("Logged in", keycloak.token);
|
|
||||||
localStorage.setItem("token", keycloak.token as string);
|
|
||||||
|
|
||||||
fetch("http://localhost:3001/profile/", {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setMounted(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleExchange = async (googleResponse: GoogleAuthResponse): Promise<void> => {
|
const handleExchange = async (googleResponse: GoogleAuthResponse): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
const details: Record<string, string> = {
|
const details: Record<string, string> = {
|
||||||
@@ -190,11 +169,7 @@ export default function AppleStyleAuth() {
|
|||||||
|
|
||||||
{/* 4. BOTÃO GOOGLE */}
|
{/* 4. BOTÃO GOOGLE */}
|
||||||
<button
|
<button
|
||||||
onClick={() =>
|
onClick={() => (window.location.href = "/api/auth/login")}
|
||||||
keycloak.login({
|
|
||||||
redirectUri: `${window.location.origin}/create-news`,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
className="group flex w-full items-center justify-center gap-3 rounded-2xl border border-neutral-200 bg-white px-6 py-3.5 transition-all hover:bg-neutral-50 active:scale-[0.98] dark:border-neutral-800 dark:bg-transparent dark:hover:bg-neutral-900"
|
className="group flex w-full items-center justify-center gap-3 rounded-2xl border border-neutral-200 bg-white px-6 py-3.5 transition-all hover:bg-neutral-50 active:scale-[0.98] dark:border-neutral-800 dark:bg-transparent dark:hover:bg-neutral-900"
|
||||||
>
|
>
|
||||||
<svg className="h-5 w-5" viewBox="0 0 24 24">
|
<svg className="h-5 w-5" viewBox="0 0 24 24">
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
|
export async function GET(req: Request) {
|
||||||
|
const url = new URL(req.url);
|
||||||
|
const code = url.searchParams.get("code");
|
||||||
|
|
||||||
|
// exchange code for token (Keycloak token endpoint)
|
||||||
|
const tokenRes = await fetch("https://keycloak.petermaquiran.xyz/realms/tvone/protocol/openid-connect/token", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||||
|
body: new URLSearchParams({
|
||||||
|
client_id: "tvone-web",
|
||||||
|
client_secret: "7jQUciQCCf2WRFRe170UANKzGKVWFIkY",
|
||||||
|
grant_type: "authorization_code",
|
||||||
|
code: code!,
|
||||||
|
redirect_uri: "http://localhost:3000/api/auth/callback",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const text = await tokenRes.text();
|
||||||
|
var data = JSON.parse(text);
|
||||||
|
|
||||||
|
const res = NextResponse.redirect("http://localhost:3000/dashboard");
|
||||||
|
|
||||||
|
res.cookies.set("access_token", data.access_token, {
|
||||||
|
httpOnly: true,
|
||||||
|
secure: true,
|
||||||
|
sameSite: "lax",
|
||||||
|
path: "/",
|
||||||
|
});
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
export async function GET() {
|
||||||
|
const redirect = encodeURIComponent(
|
||||||
|
"http://localhost:3000/api/auth/callback"
|
||||||
|
);
|
||||||
|
|
||||||
|
const keycloakUrl =
|
||||||
|
`https://keycloak.petermaquiran.xyz/realms/tvone/protocol/openid-connect/auth` +
|
||||||
|
`?client_id=tvone-web` +
|
||||||
|
`&response_type=code` +
|
||||||
|
`&scope=openid` +
|
||||||
|
`&redirect_uri=${redirect}`;
|
||||||
|
|
||||||
|
return Response.redirect(keycloakUrl);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
export async function GET() {
|
||||||
|
const redirect = encodeURIComponent(
|
||||||
|
"http://localhost:3000/api/auth/callback"
|
||||||
|
);
|
||||||
|
|
||||||
|
const keycloakUrl =
|
||||||
|
`https://keycloak.petermaquiran.xyz/auth/realms/tvone/protocol/openid-connect/auth` +
|
||||||
|
`?client_id=tvone-web` +
|
||||||
|
`&response_type=code` +
|
||||||
|
`&scope=openid` +
|
||||||
|
`&redirect_uri=${redirect}`;
|
||||||
|
|
||||||
|
return Response.redirect(keycloakUrl);
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { NextResponse } from "next/server";
|
||||||
|
|
||||||
|
export async function POST(req: Request) {
|
||||||
|
const { token } = await req.json();
|
||||||
|
|
||||||
|
const res = NextResponse.json({ ok: true });
|
||||||
|
|
||||||
|
res.cookies.set("auth_token", token, {
|
||||||
|
httpOnly: true,
|
||||||
|
secure: true,
|
||||||
|
sameSite: "lax",
|
||||||
|
path: "/",
|
||||||
|
});
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
@@ -1,29 +1,29 @@
|
|||||||
import Keycloak from "keycloak-js";
|
// import Keycloak from "keycloak-js";
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* KEYCLOAK CONFIGURATION
|
// * KEYCLOAK CONFIGURATION
|
||||||
* Logic: Environment variable validation and OIDC configuration.
|
// * Logic: Environment variable validation and OIDC configuration.
|
||||||
*/
|
// */
|
||||||
|
|
||||||
export const keycloakConfig = {
|
// export const keycloakConfig = {
|
||||||
clientId: process.env.KEYCLOAK_CLIENT_ID!,
|
// clientId: process.env.KEYCLOAK_CLIENT_ID!,
|
||||||
clientSecret: process.env.KEYCLOAK_CLIENT_SECRET!,
|
// clientSecret: process.env.KEYCLOAK_CLIENT_SECRET!,
|
||||||
issuer: `${process.env.KEYCLOAK_ISSUER_URL}/realms/${process.env.KEYCLOAK_REALM}`,
|
// issuer: `${process.env.KEYCLOAK_ISSUER_URL}/realms/${process.env.KEYCLOAK_REALM}`,
|
||||||
|
|
||||||
// Scopes needed for OIDC and profile access
|
// // Scopes needed for OIDC and profile access
|
||||||
scope: 'openid profile email',
|
// scope: 'openid profile email',
|
||||||
|
|
||||||
// Endpoint for global logout
|
// // Endpoint for global logout
|
||||||
endSessionEndpoint: `${process.env.KEYCLOAK_ISSUER_URL}/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/logout`,
|
// endSessionEndpoint: `${process.env.KEYCLOAK_ISSUER_URL}/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/logout`,
|
||||||
};
|
// };
|
||||||
|
|
||||||
// Simple check to ensure environment variables are present
|
// // Simple check to ensure environment variables are present
|
||||||
if (!process.env.KEYCLOAK_CLIENT_ID || !process.env.KEYCLOAK_ISSUER_URL) {
|
// if (!process.env.KEYCLOAK_CLIENT_ID || !process.env.KEYCLOAK_ISSUER_URL) {
|
||||||
console.warn("Auth Warning: Keycloak environment variables are missing.");
|
// console.warn("Auth Warning: Keycloak environment variables are missing.");
|
||||||
}
|
// }
|
||||||
|
|
||||||
export const keycloak = new Keycloak({
|
// export const keycloak = new Keycloak({
|
||||||
url: "https://keycloak.petermaquiran.xyz",
|
// url: "https://keycloak.petermaquiran.xyz",
|
||||||
realm: "tvone", // ✅ IMPORTANT
|
// realm: "tvone", // ✅ IMPORTANT
|
||||||
clientId: "tvone-web", // must match Keycloak client
|
// clientId: "tvone-web", // must match Keycloak client
|
||||||
});
|
// });
|
||||||
Reference in New Issue
Block a user