diff --git a/.gitignore b/.gitignore index 1481c11..65433a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /server/node_modules/ /server/ka.db -/client/node_modules/ \ No newline at end of file +/client/node_modules/ +keys.txt \ No newline at end of file diff --git a/client/kb-frontend/package-lock.json b/client/kb-frontend/package-lock.json index 2209c71..52eb584 100644 --- a/client/kb-frontend/package-lock.json +++ b/client/kb-frontend/package-lock.json @@ -8,6 +8,7 @@ "name": "kb-frontend", "version": "0.0.0", "dependencies": { + "@azure/msal-browser": "^4.26.2", "react": "^18.3.1", "react-dom": "^18.3.1", "react-quill": "^2.0.0" @@ -24,6 +25,27 @@ "vite": "^7.2.4" } }, + "node_modules/@azure/msal-browser": { + "version": "4.26.2", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.26.2.tgz", + "integrity": "sha512-F2U1mEAFsYGC5xzo1KuWc/Sy3CRglU9Ql46cDUx8x/Y3KnAIr1QAq96cIKCk/ZfnVxlvprXWRjNKoEpgLJXLhg==", + "license": "MIT", + "dependencies": { + "@azure/msal-common": "15.13.2" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "15.13.2", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.13.2.tgz", + "integrity": "sha512-cNwUoCk3FF8VQ7Ln/MdcJVIv3sF73/OT86cRH81ECsydh7F4CNfIo2OAx6Cegtg8Yv75x4506wN4q+Emo6erOA==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", diff --git a/client/kb-frontend/package.json b/client/kb-frontend/package.json index e813f8b..b239c5e 100644 --- a/client/kb-frontend/package.json +++ b/client/kb-frontend/package.json @@ -10,6 +10,7 @@ "preview": "vite preview" }, "dependencies": { + "@azure/msal-browser": "^4.26.2", "react": "^18.3.1", "react-dom": "^18.3.1", "react-quill": "^2.0.0" diff --git a/client/kb-frontend/src/components/Login.css b/client/kb-frontend/src/components/Login.css index b3e02d7..00883a0 100644 --- a/client/kb-frontend/src/components/Login.css +++ b/client/kb-frontend/src/components/Login.css @@ -104,4 +104,59 @@ .link-button:disabled { color: #95a5a6; cursor: not-allowed; +} + +.divider { + margin: 1.5rem 0; + text-align: center; + position: relative; +} + +.divider::before, +.divider::after { + content: ''; + position: absolute; + top: 50%; + width: 40%; + height: 1px; + background-color: #ddd; +} + +.divider::before { + left: 0; +} + +.divider::after { + right: 0; +} + +.divider span { + background-color: white; + padding: 0 1rem; + color: #999; +} + +.microsoft-login-button { + width: 100%; + padding: 0.75rem; + background-color: white; + color: #5e5e5e; + border: 1px solid #8c8c8c; + border-radius: 4px; + font-size: 1rem; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + transition: background-color 0.3s; +} + +.microsoft-login-button:hover:not(:disabled) { + background-color: #f5f5f5; +} + +.microsoft-login-button:disabled { + opacity: 0.6; + cursor: not-allowed; } \ No newline at end of file diff --git a/client/kb-frontend/src/components/Login.jsx b/client/kb-frontend/src/components/Login.jsx index 3300bd4..cfb0318 100644 --- a/client/kb-frontend/src/components/Login.jsx +++ b/client/kb-frontend/src/components/Login.jsx @@ -1,4 +1,6 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; +import { PublicClientApplication } from '@azure/msal-browser'; +import { msalConfig, loginRequest } from '../msalConfig'; import './Login.css'; function Login({ onLoginSuccess, onSwitchToRegister }) { @@ -6,6 +8,17 @@ function Login({ onLoginSuccess, onSwitchToRegister }) { const [password, setPassword] = useState(''); const [error, setError] = useState(''); const [loading, setLoading] = useState(false); + const [msalInstance, setMsalInstance] = useState(null); + + useEffect(() => { + const initializeMasal = async () => { + const instance = new PublicClientApplication(msalConfig); + await instance.initialize(); + setMsalInstance(instance); + }; + + initializeMasal(); + }, []); const handleSubmit = async (e) => { e.preventDefault(); @@ -39,6 +52,45 @@ function Login({ onLoginSuccess, onSwitchToRegister }) { } }; + const handleMicrosoftLogin = async () => { + if (!msalInstance) { + setError('Microsoft login is initializing, please try again'); + return; + } + + setLoading(true); + setError(''); + + try { + // Trigger Microsoft login popup - this gets us the access token directly + const loginResponse = await msalInstance.loginPopup(loginRequest); + + // Send the access token to your backend + const response = await fetch('http://localhost:9000/api/auth/microsoft', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + accessToken: loginResponse.accessToken // Send access token instead of code + }) + }); + + const data = await response.json(); + + if (response.ok) { + onLoginSuccess(data.user, data.token); + } else { + setError(data.error || 'Microsoft login failed'); + } + } catch (err) { + console.error('Microsoft login error:', err); + setError('Failed to login with Microsoft'); + } finally { + setLoading(false); + } + }; + return (