diff --git a/.env.example b/.env.example
index eec80f9..0eb803c 100644
--- a/.env.example
+++ b/.env.example
@@ -1,5 +1,10 @@
NODE_ID=aUniqueString
+REACT_APP_GITHUB_OAUTH=https://github.com/login/oauth/authorize?client_id=CLIENT_ID_HERE&redirect_uri=http://localhost:8080/oauth/redirect
+CLIENT_REDIRECT_AFTER_OAUTH=http://localhost:3000/auth-successful
+
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
GITHUB_USER_AGENT=
+
+JWT_SECRET=aVerySecretJwtSigningSecret
\ No newline at end of file
diff --git a/config/runtime.exs b/config/runtime.exs
index ec1e7dc..88a1696 100644
--- a/config/runtime.exs
+++ b/config/runtime.exs
@@ -3,7 +3,12 @@ import Config
config :chessh, Web,
github_client_id: System.get_env("GITHUB_CLIENT_ID"),
github_client_secret: System.get_env("GITHUB_CLIENT_SECRET"),
- github_user_agent: System.get_env("GITHUB_USER_AGENT")
+ github_user_agent: System.get_env("GITHUB_USER_AGENT"),
+ client_redirect_after_successful_sign_in:
+ System.get_env("CLIENT_REDIRECT_AFTER_OAUTH", "http://localhost:3000")
+
+config :joken,
+ default_signer: System.get_env("JWT_SECRET")
if config_env() == :prod do
database_url =
diff --git a/front/src/context/auth_context.js b/front/src/context/auth_context.js
new file mode 100644
index 0000000..bce9e0f
--- /dev/null
+++ b/front/src/context/auth_context.js
@@ -0,0 +1,104 @@
+import React, { useContext, useState, createContext, useEffect } from "react";
+
+export const DEFAULT_EXPIRY_TIME_MS = 12 * 60 * 60 * 1000;
+
+const AuthContext = createContext({
+ signedIn: false,
+ setSignedIn: () => null,
+ sessionOver: new Date(),
+ setSessionOver: () => null,
+ userId: null,
+ setUserId: () => null,
+ username: "",
+ setUsername: () => null,
+});
+
+export const useAuthContext = () => useContext(AuthContext);
+
+export const AuthProvider = ({ children }) => {
+ const [signedIn, setSignedIn] = useState(false);
+ const [sessionOver, setSessionOver] = useState(new Date());
+ const [userId, setUserId] = useState(null);
+ const [username, setUsername] = useState(null);
+
+ useEffect(() => {
+ if (!signedIn) {
+ setUsername(null);
+ setUserId(null);
+ }
+ }, [signedIn]);
+
+ useEffect(() => {
+ if (userId) {
+ localStorage.setItem("userId", userId.toString());
+ }
+ }, [userId]);
+
+ useEffect(() => {
+ if (username) {
+ localStorage.setItem("username", username);
+ }
+ }, [username]);
+
+ useEffect(() => {
+ let expiry = localStorage.getItem("expiry");
+ if (expiry) {
+ expiry = new Date(expiry);
+ if (Date.now() < expiry.getTime()) {
+ setSignedIn(true);
+ setSessionOver(expiry);
+ // We don't have access to the JWT token as it is an HTTP only cookie -
+ // so we store user info in local storage
+ ((username) => {
+ if (username) {
+ setUsername(username);
+ }
+ })(localStorage.getItem("username"));
+
+ ((id) => {
+ if (id) {
+ setUserId(parseInt(id, 10));
+ }
+ })(localStorage.getItem("userId"));
+ }
+ }
+ }, []);
+
+ useEffect(() => {
+ localStorage.setItem("expiry", sessionOver.toISOString());
+ setTimeout(() => {
+ setSessionOver((sessionOver) => {
+ if (Date.now() >= sessionOver.getTime()) {
+ setSignedIn((signedIn) => {
+ if (signedIn) {
+ alert(
+ "Session expired. Any further privileged requests will fail until signed in again."
+ );
+ ["userId", "userName"].map((x) => localStorage.removeItem(x));
+ return false;
+ }
+ return signedIn;
+ });
+ }
+ return sessionOver;
+ });
+ }, sessionOver.getTime() - Date.now());
+ }, [sessionOver]);
+
+ return (
+
Hello there, {username || ""}
:Loading...
} + > + ); +}; diff --git a/front/src/routes/demo.jsx b/front/src/routes/demo.jsx index ca07758..951ed91 100644 --- a/front/src/routes/demo.jsx +++ b/front/src/routes/demo.jsx @@ -26,14 +26,14 @@ export const Demo = () => { ); setRenderedPlayer(true); } - }, [player]); + }, [renderedPlayer, player]); return ( -CheSSH is a multiplayer, scalable, free, open source, and potentially passwordless game of Chess over the SSH protocol. @@ -42,6 +42,7 @@ export const Demo = () => { className="button gold" href="https://github.com/Simponic/chessh" target="_blank" + rel="noreferrer" > 🌟 Star 🌟 @@ -49,10 +50,10 @@ export const Demo = () => {