Skip to content

Commit

Permalink
Setup Authentication (login/logout only) πŸ”πŸ”πŸ”πŸ‘©β€πŸ”¬πŸ‘©β€πŸ”¬πŸ‘©β€πŸ”¬
Browse files Browse the repository at this point in the history
- requests to AWS Cognito UserPool πŸ•΅οΈ

- this can be extended to add forgot password and reset password methods too

- this can replaced to use different auth providers

- giving all CMS routes access to authentication context
  • Loading branch information
arnard76 committed Apr 25, 2024
1 parent dbb17f6 commit 67936ee
Show file tree
Hide file tree
Showing 5 changed files with 315 additions and 11 deletions.
4 changes: 2 additions & 2 deletions cypress/e2e/authentication.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ describe("Authentication", () => {
})
);

cy.visit(URLS.LOGIN_URL);
cy.url().should("eq", URLS.LOGIN_URL);
cy.visit(URLS.LOGIN);
cy.url().should("eq", URLS.LOGIN);
cy.get("button")
.contains("Logout", { matchCase: false })
.should("not.exist");
Expand Down
18 changes: 9 additions & 9 deletions frontend/app/(cms)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"use client";

import React from "react";
import AuthProvider from "@/app/cms-authentication/AuthContext";

export default function CMSLayout({ children, }: { children: React.ReactNode }) {
return (
<div>
{/*<div className={"absolute right-12 -z-50"}>*/}
{/* <p className={"opacity-55 text-sm text-blue-500"}>CMS Layout</p>*/}
{/*</div>*/}
{children}
</div>
)
export default function CMSLayout({ children }: { children: React.ReactNode }) {
return (
<AuthProvider>
<div>{children}</div>
</AuthProvider>
);
}
114 changes: 114 additions & 0 deletions frontend/app/cms-authentication/AuthContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import React, { useContext, useState, useEffect } from "react";
import {
AuthenticationDetails,
CognitoUser,
CognitoUserPool,
CognitoUserSession,
CognitoIdToken,
} from "amazon-cognito-identity-js";
import { redirect } from "next/navigation";

type AuthContextValue = {
currentUser: null | CognitoIdToken["payload"];
login: any;
logout: any;
};

const openRoutes = ["/login", "/forgot-password"];

// where to authenticate users from
const adminUserPool = new CognitoUserPool({
ClientId: "7dv8g7lsl2ht3uv29q9npt0a84",
UserPoolId: "us-east-1_1GuGm8wMs",
});

const AuthContext = React.createContext({
currentUser: null,
login: () => {},
} as AuthContextValue);

export function useAuth() {
return useContext(AuthContext);
}

export default function AuthProvider({ children }: React.PropsWithChildren) {
const [currentUserSession, setCurrentUserSession] = useState(
null as AuthContextValue["currentUser"]
);
const [loading, setLoading] = useState(true);

useEffect(() => {
const currentUser = adminUserPool.getCurrentUser();

if (!currentUser) return setLoading(false);

currentUser.getSession(
(error: Error | null, session: CognitoUserSession | null) => {
error && console.log("Error in getting user session:", error);
session && setCurrentUserSession(session.getIdToken().payload);
setLoading(false);
}
);
}, []);

useEffect(() => {
if (loading) return; // we don't know if user is logged in or not

const currentRoute = window.location.pathname;

if (!currentUserSession && !openRoutes.includes(currentRoute)) {
redirect(openRoutes[0]);
}

if (currentUserSession && openRoutes.includes(currentRoute)) {
redirect("/news/publish/");
}

setLoading(false);
}, [currentUserSession, loading]);

async function login(email: string, password: string) {
const user = new CognitoUser({
Username: email,
Pool: adminUserPool,
});

const authDetails = new AuthenticationDetails({
Username: email,
Password: password,
});

try {
const result: CognitoUserSession = await new Promise(
(resolve, reject) => {
user.authenticateUser(authDetails, {
onSuccess: resolve,
onFailure: reject,
});
}
);

setCurrentUserSession(result.getIdToken().payload);
} catch (error) {
console.error("Login failed:", error);
}
}

function logout() {
adminUserPool.getCurrentUser()?.signOut();
setCurrentUserSession(null);
}

// expose useful auth methods/values
const authDetails = {
currentUser: currentUserSession,
login,
logout,
};

return (
<AuthContext.Provider value={authDetails}>
{!loading && children}
</AuthContext.Provider>
);
}
Loading

0 comments on commit 67936ee

Please sign in to comment.