Skip to content

Instantly share code, notes, and snippets.

@kauffmanes
Last active January 2, 2022 01:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kauffmanes/131621c52778d62e74819f2812a098c6 to your computer and use it in GitHub Desktop.
Save kauffmanes/131621c52778d62e74819f2812a098c6 to your computer and use it in GitHub Desktop.
// FILE #1: app/utils/session.ts
import jwt from 'jsonwebtoken';
import { redirect } from 'remix';
export function requireValidSession(request: Request) {
// assuming key is stored as base64
// if not, no need for this line, just use env var directly
const publicKey = Buffer.from(process.env.JWT_PUBLIC_KEY || '', 'base64').toString('ascii');
const tokenName = process.env.USERFRONT_TOKEN_NAME || '';
if (!tokenName) {
throw redirect('/login', 401);
}
const cookieObj = parseCookie(request.headers.get("Cookie"));
const accessToken = cookieObj.hasOwnProperty(tokenName) && cookieObj[tokenName] || null;
if (!accessToken || !publicKey) {
throw redirect('/login', 401);
}
try {
const verifiedPayload = jwt.verify(accessToken, publicKey, { algorithms: ['RS256'] });
return verifiedPayload;
} catch(err) {
throw redirect('/login', 401);
}
}
// https://www.30secondsofcode.org/js/s/parse-cookie
function parseCookie(str: string | null) {
if (!str) return {};
return str.split(';').map(v => v.split('='))
.reduce((acc: any, v) => {
acc[decodeURIComponent(v[0].trim())] = decodeURIComponent(v[1].trim());
return acc;
}, {});
}
// FILE #2: Protected Route
import { useLoaderData } from 'remix';
import { requireValidSession } from "../../utils/session";
export async function loader({ request }: { request: Request }) {
export async function loader({ request }: { request: Request }) {
return requireValidSession(request);
}
export default function Dashboard() {
const userData = useLoaderData();
return (
<div>
Welcome to the Dashboard!
{JSON.stringify(userData)}
</div>
);
}
@kauffmanes
Copy link
Author

I spent a few days trying to figure out how to use Userfront with Remix Run. Caveat to this code: it works but I'm not confident it's the most secure or best way to do this. I think I would have preferred to use Remix built-in functions but I couldn't get it working. If you have a better way of doing it, please post!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment