Skip to content

Instantly share code, notes, and snippets.

@infomiho
Created July 29, 2024 22:13
Show Gist options
  • Save infomiho/baf8330ce3733c64906173b1533f2f45 to your computer and use it in GitHub Desktop.
Save infomiho/baf8330ce3733c64906173b1533f2f45 to your computer and use it in GitHub Desktop.
Custom login API endpoint
app apiAuth {
wasp: {
version: "^0.14.0"
},
title: "api-auth",
auth: {
userEntity: User,
onAuthFailedRedirectTo: "/login",
onAuthSucceededRedirectTo: "/",
methods: {
usernameAndPassword: {}
}
}
}
route RootRoute { path: "/", to: MainPage }
page MainPage {
component: import { MainPage } from "@src/MainPage",
authRequired: true
}
route LoginRoute { path: "/login", to: Login }
page Login {
component: import { LoginPage } from "@src/auth"
}
route SignupRoute { path: "/signup", to: Signup }
page Signup {
component: import { SignupPage } from "@src/auth"
}
api customLogin {
httpRoute: (POST, "/api/custom-login"),
fn: import { customLogin } from "@src/api",
entities: []
}
apiNamespace customApiNamespace {
middlewareConfigFn: import { getMiddleware } from "@src/api",
path: "/api"
}
import { CustomLogin } from "wasp/server/api";
import { prisma } from "wasp/server";
import { createSession } from "wasp/auth/session";
import { deserializeAndSanitizeProviderData } from "wasp/auth/utils";
import { verifyPassword } from "wasp/auth/password";
import { MiddlewareConfigFn } from "wasp/server/middleware";
type Params = {};
type Response =
| {
sessionId: string;
}
| {
message: string;
};
type Body = {
username: string;
password: string;
};
export const customLogin: CustomLogin<Params, Response, Body> = async (
req,
res
) => {
// 1. Receive username and password - ideally you'd validate this
const { username, password } = req.body;
// 2. Locate the user by username auth identity
const authIdentityWithUser = await prisma.authIdentity.findUnique({
where: {
providerName_providerUserId: {
providerName: "username",
providerUserId: username,
},
},
include: {
auth: {
include: {
user: true,
},
},
},
});
// 3. If user not found, return 401
if (!authIdentityWithUser) {
res.status(401).json({ message: "Invalid username or password" });
return;
}
// 4. Grab the hashed password from the auth identity
const providerData = deserializeAndSanitizeProviderData<"username">(
authIdentityWithUser.providerData
);
try {
// 5. Verify the password
await verifyPassword(providerData.hashedPassword, password);
// 6a. If password verification succeeds, create a session
const session = await createSession(authIdentityWithUser.auth.id);
// 7. Return the session id - which can be used to authenticate the user in subsequent requests
// (by sending it in the Authorization header)
return res.json({ sessionId: session.id });
} catch (e) {
// 6a. If password verification fails, return 401
res.status(401).json({ message: "Invalid username or password" });
}
};
// Setting the default middleware for the /api endpoint
// This way we get CORS and JSON parsing out of the box
export const getMiddleware: MiddlewareConfigFn = (config) => {
// Logger is already applied to the POST /api/custom-login endpoint
config.delete("logger");
return config;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment