Skip to content

Commit

Permalink
feat: redis-backed sessions
Browse files Browse the repository at this point in the history
  • Loading branch information
horsefacts committed Feb 1, 2024
1 parent 3d43632 commit f6b5bdf
Show file tree
Hide file tree
Showing 12 changed files with 70 additions and 16 deletions.
Binary file modified web/bun.lockb
Binary file not shown.
20 changes: 20 additions & 0 deletions web/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
version: "3.9"

services:
redis:
image: "redis:7.2-alpine"
restart: unless-stopped
command: --save 1 1 --loglevel warning --maxmemory-policy noeviction
volumes:
- redis-data:/data
ports:
- "6379:6379"
healthcheck:
test: ["CMD-SHELL", "redis-cli", "ping"]
interval: 10s
timeout: 10s
retries: 3
start_period: 5s

volumes:
redis-data:
1 change: 1 addition & 0 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@farcaster/auth-kit": "0.2.0",
"@farcaster/core": "^0.13.4",
"date-fns": "^3.3.1",
"ioredis": "^5.3.2",
"linkify-it": "^5.0.0",
"linkify-react": "^4.1.3",
"next": "14.1.0",
Expand Down
2 changes: 1 addition & 1 deletion web/src/app/api/auth/sign-in/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export async function POST(request: Request) {
const token = randomUUID();
const fid = verifyResult.fid.toString();

setCurrentUser({ token, fid });
await setCurrentUser({ token, fid });

return NextResponse.json({ fid, token });
}
2 changes: 1 addition & 1 deletion web/src/app/api/auth/sign-out/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import { clearCurrentUser } from '@lib/auth/clearCurrentUser';
import { NextResponse } from 'next/server';

export async function POST() {
clearCurrentUser();
await clearCurrentUser();
return NextResponse.json({ success: true });
}
4 changes: 2 additions & 2 deletions web/src/components/logout/Logout.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
'use client';
"use client";

export default function Logout() {
return (
<button
type="button"
className="bg-fc-purple cursor-pointer rounded px-4 py-2 text-white"
onClick={async () => {
await fetch('/api/auth/sign-out');
await fetch("/api/auth/sign-out", { method: "POST" });
window.location.reload();
}}
>
Expand Down
11 changes: 6 additions & 5 deletions web/src/lib/auth/clearCurrentUser.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { cookies } from 'next/headers';
import { clearSessionToken } from "@lib/redis/sessions";
import { cookies } from "next/headers";

import { getTokenFromCookieOrHeader } from './getTokenFromCookieOrHeader';
import { tokenKey, tokens } from './shared';
import { getTokenFromCookieOrHeader } from "./getTokenFromCookieOrHeader";
import { tokenKey } from "./shared";

export function clearCurrentUser() {
export async function clearCurrentUser() {
const token = getTokenFromCookieOrHeader();

cookies().delete(tokenKey);

if (token) {
delete tokens[token];
await clearSessionToken({ token });
}
}
5 changes: 3 additions & 2 deletions web/src/lib/auth/getCurrentUser.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { getSessionByToken } from '@lib/redis/sessions';
import { getProfile } from '@lib/services/user';
import { User } from '@shared/types/models';

import { getTokenFromCookieOrHeader } from './getTokenFromCookieOrHeader';
import { tokens } from './shared';

export async function getCurrentUser(): Promise<User | null> {
const token = getTokenFromCookieOrHeader();
Expand All @@ -11,7 +11,8 @@ export async function getCurrentUser(): Promise<User | null> {
return null;
}

const fid = tokens[token];
const res = await getSessionByToken({ token });
const { fid } = res;

if (!fid) {
return null;
Expand Down
7 changes: 4 additions & 3 deletions web/src/lib/auth/setCurrentUser.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { setSessionToken } from '@lib/redis/sessions';
import { cookies } from 'next/headers';

import { tokenKey, tokens } from './shared';
import { tokenKey } from './shared';

export function setCurrentUser({ token, fid }: { token: string; fid: string }) {
export async function setCurrentUser({ token, fid }: { token: string; fid: string }) {
cookies().set(tokenKey, token, { secure: true });
tokens[token] = fid;
return setSessionToken({ token, fid });
}
3 changes: 1 addition & 2 deletions web/src/lib/auth/shared.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export const tokenKey = 'token';
export const tokens: Record<string, string> = {};
export const tokenKey = "token";
3 changes: 3 additions & 0 deletions web/src/lib/redis/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Redis from 'ioredis';

export const redis = new Redis(process.env.REDIS_URL ?? "redis://localhost:6379");
28 changes: 28 additions & 0 deletions web/src/lib/redis/sessions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { tokenKey } from "@lib/auth/shared";

import { redis } from "./client";

const ttl = 60 * 60 * 24 * 30;

interface Session {
fid?: string;
}

export async function setSessionToken({
token,
fid,
}: {
token: string;
fid: string;
}) {
return redis.set(`${tokenKey}:${token}`, JSON.stringify({ fid }), "EX", ttl);
}

export async function clearSessionToken({ token }: { token: string }) {
return redis.del(`${tokenKey}:${token}`);
}

export async function getSessionByToken({ token }: { token: string }) {
const session = (await redis.get(`${tokenKey}:${token}`)) ?? "{}";
return JSON.parse(session) as Session;
}

0 comments on commit f6b5bdf

Please sign in to comment.