Logout Functionality
Learning objectives
- You know how to add logout functionality to a web application.
So far, our application allows logging in and registering new users. However, there is no way to log out. Let's add the logout functionality next.
Logout button
Let's start by adding a button for logging out. When the user presses the button, a POST request is sent to the path "/auth/logout". The logout button should be visible only when the user is logged in -- the following outlines a modification to our earlier main.eta
template.
<!DOCTYPE html>
<html>
<head>
<title>Hello user management!</title>
</head>
<body>
<% if (it && it.user) { %>
<p>Hi <%= it.user.email %>!</p>
<form method="POST" action="/auth/logout">
<input type="submit" value="Logout" />
</form>
<% } else { %>
<p>Hi guest!</p>
<p>Please <a href="/auth/login">login</a> or <a href="/auth/registration">register</a>.</p>
<% } %>
</body>
</html>
Why not a logout link?
You might wonder why we use a form for the logout functionality instead of a link. In HTTP, GET requests are intended for requests that do not change the state of the server, while POST requests can change the state of the server. Using a link would create a GET request, while when we implement the logout functionality using a form with the method POST, we conform to the expectations of the HTTP protocol.
Handling the logout request
To handle the logout, add a new route, POST to /auth/logout
to app.js
, mapping the request to a logoutUser
function of authController.js
.
import { Hono } from "https://deno.land/x/hono@v3.12.11/mod.ts";
import * as authController from "./authController.js";
import * as mainController from "./mainController.js";
const app = new Hono();
app.get("/auth/login", authController.showLoginForm);
app.post("/auth/login", authController.loginUser);
app.get("/auth/registration", authController.showRegistrationForm);
app.post("/auth/registration", authController.registerUser);
app.post("/auth/logout", authController.logoutUser);
app.get("/", mainController.showMain);
Deno.serve(app.fetch);
The logoutUser
function should delete the session and redirect the user to the main page. The function does not exist yet though, so making a POST request to the path leads to an error. Time to implement the function.
In the authController.js
file, the functionality for logging out can be relatively straightforward. We'll essentially just call a function for deleting the session -- deleteSession
-- form the session service, and redirect the user back to the main page. This is implemented as follows.
const logoutUser = async (c) => {
await sessionService.deleteSession(c);
return c.redirect("/");
};
Deleting the session
Deleting the session requires deleting the cookie and removing the associated session information from Deno KV. For deleting a cookie, we'll use the deleteCookie
function from Hono's cookie helpers. For deleting the session information from Deno KV, we'll use the delete
function from the kv.ts
file.
First, we need to find the cookied though -- this is done by using the getSignedCookie
function. If the cookie does not exist, we'll just skip the rest of the logging out. Otherwise, we'll use the deleteCookie
method, which takes the context and the cookie id as a parameter. We'll also pass an object with the path of the cookie, which is /
in our case.
Finally, we'll remove the session from Deno KV using the delete
method, passing the key to the session as a parameter. The key is an array with two elements: the first element is the name of the namespace, which is sessions
in our case, and the second element is the session id.
import {
deleteCookie,
getSignedCookie,
setSignedCookie,
} from "https://deno.land/x/hono@v3.12.11/helper.ts";
// ...
const deleteSession = async (c) => {
const sessionId = await getSignedCookie(c, secret, "sessionId");
if (!sessionId) {
return;
}
deleteCookie(c, "sessionId", {
path: "/",
});
const kv = await Deno.openKv();
await kv.delete(["sessions", sessionId]);
};
// ...
Now, we can also logout from the system. Try it out! You should be able to log in, and then log out. After logging out, you should be redirected to the main page, and the logout button should be gone.