basic auth
parent
0b1c246fe2
commit
32f03a452b
@ -1,6 +1,9 @@
|
|||||||
import Elysia from "elysia";
|
import Elysia from "elysia";
|
||||||
import { todosController } from "./todos";
|
import { todosController } from "./todos";
|
||||||
|
import { authController } from "./auth";
|
||||||
|
|
||||||
export const api = new Elysia({
|
export const api = new Elysia({
|
||||||
prefix: "/api",
|
prefix: "/api",
|
||||||
}).use(todosController);
|
})
|
||||||
|
.use(todosController)
|
||||||
|
.use(authController);
|
||||||
|
@ -1,5 +1,75 @@
|
|||||||
import { Elysia } from "elysia";
|
import { Elysia, t } from "elysia";
|
||||||
|
import { ctx } from "../context";
|
||||||
|
import { set } from "zod";
|
||||||
|
|
||||||
|
class DuplicateEmailError extends Error {
|
||||||
|
constructor() {
|
||||||
|
super("Duplicate email");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const authController = new Elysia({
|
export const authController = new Elysia({
|
||||||
prefix: "/auth",
|
prefix: "/auth",
|
||||||
}).post("/signup", "signup");
|
})
|
||||||
|
.use(ctx)
|
||||||
|
.post(
|
||||||
|
"/signup",
|
||||||
|
async ({ body: { email, password }, auth, set }) => {
|
||||||
|
const user = await auth
|
||||||
|
.createUser({
|
||||||
|
key: {
|
||||||
|
providerId: "email", // auth method
|
||||||
|
providerUserId: email.toLowerCase(), // unique id when using "email" auth method
|
||||||
|
password, // hashed by Lucia
|
||||||
|
},
|
||||||
|
attributes: {
|
||||||
|
email,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
if (err.code === "SQLITE_CONSTRAINT") {
|
||||||
|
throw new DuplicateEmailError();
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const session = await auth.createSession({
|
||||||
|
userId: user.userId,
|
||||||
|
attributes: {},
|
||||||
|
});
|
||||||
|
const sessionCookie = auth.createSessionCookie(session);
|
||||||
|
|
||||||
|
set.headers["Set-Cookie"] = sessionCookie.serialize();
|
||||||
|
set.redirect = "/profile";
|
||||||
|
},
|
||||||
|
{
|
||||||
|
body: t.Object({
|
||||||
|
email: t.String({
|
||||||
|
minLength: 5,
|
||||||
|
maxLength: 30,
|
||||||
|
}),
|
||||||
|
password: t.String({
|
||||||
|
minLength: 6,
|
||||||
|
maxLength: 255,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
error({ code, error, set }) {
|
||||||
|
if (code === "VALIDATION") {
|
||||||
|
console.log("sign up validation error");
|
||||||
|
console.log(error);
|
||||||
|
set.status = 400;
|
||||||
|
return "Invalid email or password";
|
||||||
|
} else if (error instanceof DuplicateEmailError) {
|
||||||
|
console.log("sign up duplicate email error");
|
||||||
|
console.log(error);
|
||||||
|
set.status = 400;
|
||||||
|
return "Email already exists";
|
||||||
|
} else {
|
||||||
|
console.log("sign up error");
|
||||||
|
console.log(error);
|
||||||
|
set.status = 500;
|
||||||
|
return "Internal server error";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
import Elysia from "elysia";
|
||||||
|
import { signup } from "./signup";
|
||||||
|
import { profile } from "./profile";
|
||||||
|
|
||||||
|
export const authGroup = new Elysia().use(signup).use(profile);
|
@ -0,0 +1,16 @@
|
|||||||
|
import Elysia from "elysia";
|
||||||
|
import { BaseHtml } from "../../components/base";
|
||||||
|
import { ctx } from "../../context";
|
||||||
|
|
||||||
|
export const profile = new Elysia()
|
||||||
|
.use(ctx)
|
||||||
|
.get("/profile", async ({ auth, html, request }) => {
|
||||||
|
const authRequest = auth.handleRequest(request);
|
||||||
|
|
||||||
|
const session = await authRequest.validate();
|
||||||
|
if (session) {
|
||||||
|
return html(<div>Hello {session.user.email}</div>);
|
||||||
|
} else {
|
||||||
|
return html(<div>Not logged in</div>);
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,54 @@
|
|||||||
|
import Elysia from "elysia";
|
||||||
|
import { BaseHtml } from "../../components/base";
|
||||||
|
import { ctx } from "../../context";
|
||||||
|
|
||||||
|
export const signup = new Elysia().use(ctx).get("/signup", ({ html }) =>
|
||||||
|
html(
|
||||||
|
<BaseHtml>
|
||||||
|
<div class="flex w-full h-screen bg-gray-200 justify-center items-center">
|
||||||
|
<form
|
||||||
|
hx-post="/api/auth/signup"
|
||||||
|
hx-swap="afterend"
|
||||||
|
class="bg-white p-8 rounded-lg shadow-md w-96"
|
||||||
|
>
|
||||||
|
<div class="mb-4">
|
||||||
|
<label
|
||||||
|
for="email"
|
||||||
|
class="block text-sm font-medium text-gray-600 mb-2"
|
||||||
|
>
|
||||||
|
Email
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="email"
|
||||||
|
id="email"
|
||||||
|
placeholder="Enter your email"
|
||||||
|
class="w-full p-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-400 focus:border-transparent"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<label
|
||||||
|
for="password"
|
||||||
|
class="block text-sm font-medium text-gray-600 mb-2"
|
||||||
|
>
|
||||||
|
Password
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
name="password"
|
||||||
|
id="password"
|
||||||
|
placeholder="Enter your password"
|
||||||
|
class="w-full p-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-400 focus:border-transparent"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="w-full bg-indigo-600 text-white p-2 rounded-md hover:bg-indigo-500 focus:outline-none focus:ring-2 focus:ring-indigo-400 focus:ring-opacity-50"
|
||||||
|
>
|
||||||
|
Sign Up
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</BaseHtml>
|
||||||
|
)
|
||||||
|
);
|
@ -1,4 +1,5 @@
|
|||||||
import Elysia from "elysia";
|
import Elysia from "elysia";
|
||||||
import { index } from "./index";
|
import { index } from "./index";
|
||||||
|
import { authGroup } from "./(auth)/*";
|
||||||
|
|
||||||
export const pages = new Elysia().use(index);
|
export const pages = new Elysia().use(index).use(authGroup);
|
||||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue