fastify-xauth-local
local.login
Built-in POST route that authenticates a user with email and password and returns a signed JWT.
local.login
Built-in POST {loginPath} route registered when local.enabled is true. Accepts an email and password, verifies against the userLookup function and bcrypt hash, and returns a signed JWT plus a safe user object.
Default path: {prefix}/local (e.g. /api/local)
Signature
POST {loginPath}
Content-Type: application/json
{
"email": string, // required, valid email format
"password": string // required, non-empty
}
Params
| Name | Type | Required | Description |
|---|---|---|---|
email | string | Yes | User's email address |
password | string | Yes | User's plaintext password |
Returns
200 OK:
{
"token": "eyJ...",
"user": {
"id": 1,
"email": "user@example.com",
"first_name": "Jane",
"last_name": "Doe",
"admin": false,
"color": "#abc",
"scope": ["user"]
}
}
Throws
| Status | Message | Reason |
|---|---|---|
| 401 | Invalid email or password | User not found or password mismatch |
| 500 | An error occurred during login | Unexpected server error |
This route is automatically excluded from JWT verification so it can be accessed without a token.
Examples
Basic: login request
curl -X POST http://localhost:3000/api/local \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"secret123"}'
// Use the returned token in subsequent requests
const { token } = await fetch("/api/local", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
}).then((r) => r.json());
localStorage.setItem("token", token);
Advanced: plugin registration with userLookup
await fastify.register(xAuthLocal, {
configs: [
{
name: "api",
prefix: "/api",
secret: process.env.JWT_SECRET,
local: {
enabled: true,
// userLookup must return an object with a 'password' field (bcrypt hash)
userLookup: async (email) => {
const user = await db.query(
"SELECT * FROM users WHERE email = $1",
[email]
);
return user.rows[0] ?? null;
},
},
},
],
});
// Login route is now available at POST /api/local
See Also
- local.register — create a new user account
- local.me — get the current authenticated user
- password.compare — standalone password verification
AI Context
package: "@xenterprises/fastify-xauth-local"
route: POST {loginPath} (default /api/local)
use-when: Built-in login route — authenticates with email + password and returns a signed JWT
requires: local.enabled: true, local.userLookup function
returns: { token: string }
