Skip to content

Instantly share code, notes, and snippets.

@Accudio
Created December 29, 2023 12:18
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 Accudio/a85424cd143cfbf159fa846087c0702a to your computer and use it in GitHub Desktop.
Save Accudio/a85424cd143cfbf159fa846087c0702a to your computer and use it in GitHub Desktop.
Basic authentication using Vercel edge functions
import bcrypt from 'bcrypt';
import { SignJWT } from 'jose';
import { serialize } from 'cookie';
export default async function (request, response) {
if (request.method !== "POST") {
return response.status(405).send('does not respond to GET requests');
}
// get all configured passwords
const configItems = await getEdgeConfig()
const users = Object.entries(configItems.users)
.map(([name, { password }]) => ({
name,
password
}));
// check entered password against all configured and if valid return true
for (const user of users) {
const match = bcrypt.compareSync(request.body.password, user.password);
if (match) {
const jwt = await new SignJWT({
sub: user.name
})
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setIssuer('https://xxxxxxxxx.vercel.app')
.setExpirationTime('90d')
.sign(new TextEncoder().encode(process.env.JWT_SIGNING_KEY));
const cookie = serialize(
'session',
jwt,
{
httpOnly: true,
maxAge: 7776000,
sameSite: 'lax',
path: '/'
}
)
response.setHeader('Set-Cookie', [cookie]);
return response.redirect(303, '/');
}
}
return response.redirect(303, '/auth')
}
async function getEdgeConfig() {
const res = await fetch(process.env.EDGE_CONFIG)
const json = await res.json();
return json.items
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Login</title>
</head>
<body>
<main>
<form action="/api/auth/" method="post">
<label for="password">
<div>Please enter password</div>
<input
name="password"
id="password"
type="password"
autocomplete="false"
required
/>
</label>
<button type="submit">Login</button>
</form>
</main>
</body>
</html>
import { RequestCookies } from '@edge-runtime/cookies';
import { jwtVerify } from 'jose';
export const config = {
matcher: '/',
};
export default async function middleware(request) {
try {
const cookies = new RequestCookies(request.headers)
const sessionCookie = cookies.get('session');
if (!sessionCookie) return auth(request)
await jwtVerify(
sessionCookie.value,
new TextEncoder().encode(process.env.JWT_SIGNING_KEY)
);
} catch (e) {
console.error(e)
return auth(request)
}
}
function auth(request) {
return Response.redirect(new URL('/auth', request.url), 303);
}
const bcrypt = require('bcrypt')
password()
function password() {
const password = process.argv[2]
if (!password) return console.error('no password provided')
const salt = bcrypt.genSaltSync(10)
const hash = bcrypt.hashSync(password, salt)
return console.log('Password hash:', hash)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment