passauth
v2.1.0
Published
`passauth` is a lightweight TypeScript authentication library for Node.js. It provides a ready-to-use auth handler with:
Readme
passauth
passauth is a lightweight TypeScript authentication library for Node.js.
It provides a ready-to-use auth handler with:
- User registration with hashed passwords (
bcrypt) - Login with JWT access token + refresh token flow
- Refresh token rotation and revocation
- Optional email confirmation and password reset flows
- Plugin support to extend or override handler behavior with type safety
Installation
npm install passauthRequirements
- Node.js runtime
- A user repository implementation (database adapter)
- A
secretKeyfor JWT signing
Quick start
import { Passauth, type AuthRepo, type User } from "passauth";
type AppUser = User & {
name: string;
};
const users = new Map<string, AppUser>();
const repo: AuthRepo<AppUser> = {
async getUser(params) {
if (params.email) {
return users.get(params.email) ?? null;
}
if (params.id) {
return [...users.values()].find((u) => u.id === params.id) ?? null;
}
return null;
},
async createUser(params) {
const user: AppUser = {
id: Date.now(),
email: params.email,
password: params.password,
isBlocked: false,
emailVerified: false,
name: "New User",
};
users.set(user.email, user);
return user;
},
};
const passauth = Passauth<AppUser>({
secretKey: process.env.JWT_SECRET ?? "dev-secret",
repo,
});
// Register
const user = await passauth.handler.register({
email: "[email protected]",
password: "StrongPassword123",
});
// Login
const { accessToken, refreshToken } = await passauth.handler.login({
email: user.email,
password: "StrongPassword123",
});
// Verify access token
const payload = passauth.handler.verifyAccessToken(accessToken);
// Refresh token pair
const newTokens = await passauth.handler.refreshToken(accessToken, refreshToken);
// Revoke refresh token
await passauth.handler.revokeRefreshToken(user.id);API overview
Passauth(config) returns:
{
handler: PassauthHandler,
plugins: Record<string, { handler: unknown }>
}Passauth initialization API (Passauth(config))
function Passauth<
U extends User,
P extends readonly PluginSpec<U, PassauthHandlerInt<U>, any>[]
>(config: PassauthConfiguration<U, P>): {
handler: Omit<ComposeAug<PassauthHandler<U>, P>, "_aux">;
plugins: Record<string, any>;
}PassauthConfiguration<U, P>
type PassauthConfiguration<U extends User, P = undefined> = {
secretKey: string;
repo: AuthRepo<U>;
saltingRounds?: number;
accessTokenExpirationMs?: number;
refreshTokenExpirationMs?: number;
email?: EmailHandlerOptions;
plugins?: P;
};Configuration fields (detailed)
secretKey(required) —string
Secret used to sign and validate JWT access tokens.repo(required) —AuthRepo<U>
Your persistence adapter used by auth operations (lookup user, create user, optional token cache).saltingRounds(optional) —number(default:10)
Salt rounds used for password hashing.accessTokenExpirationMs(optional) —number(default:15 * 60 * 1000)
Access token expiration time in milliseconds.refreshTokenExpirationMs(optional) —number(default:7 * 24 * 60 * 60 * 1000)
Refresh token expiration time in milliseconds.email(optional) —EmailHandlerOptions
Enables email confirmation and reset-password flows when provided.plugins(optional) —readonly PluginSpec[]
List of plugins that can override/extend the handler API.
Return value of Passauth(config)
handler— main auth API object (PassauthHandlerplus any plugin augmentations).plugins— plugin namespace object keyed by pluginname.
Repository contract (AuthRepo)
You must implement:
getUser(param: Partial<User>): Promise<User | null>createUser<P>(params: RegisterParams<P>): Promise<User>RegisterParams<P>always includesemailandpassword, and can include extra fields.
Optional methods for persistent refresh token cache (recommended in production):
getCachedToken(userId)saveCachedToken(userId, token, expiresInMs)deleteCachedToken(userId)
If cache methods are not provided, passauth keeps refresh tokens in memory.
Main handler methods
Below is a detailed reference of the methods exposed by passauth.handler.
register(params)
Creates a new user with a hashed password.
- Arguments
params(required) —RegisterParamsemail(required) —stringpassword(required) —string- Additional fields are supported (
register<T>(params: RegisterParams<T>)) and forwarded to yourrepo.createUser.
- Returns
Promise<U>— the created user entity returned by your repository.
login(params, jwtUserFields?)
Authenticates a user and returns access/refresh tokens.
- Arguments
params(required) —LoginParamsemail(required) —stringpassword(required) —string- Additional fields are supported (
login<T>(params: LoginParams<T>, ...)) and forwarded to yourrepo.getUser.
jwtUserFields(optional) —Array<keyof U>- If provided, only these user fields are injected into token payload
data.
- If provided, only these user fields are injected into token payload
- Returns
Promise<{ accessToken: string; refreshToken: string }>
verifyAccessToken(accessToken)
Validates and decodes an access token.
- Arguments
accessToken(required) —string
- Returns
AuthJwtPayload<D>— decoded payload with token claims (and optionaldata).
refreshToken(accessToken, refreshToken)
Issues a new access/refresh token pair using a valid refresh token.
- Arguments
accessToken(required) —stringrefreshToken(required) —string
- Returns
Promise<{ accessToken: string; refreshToken: string }>
revokeRefreshToken(userId)
Revokes the currently cached refresh token for a user.
- Arguments
userId(required) —ID(string | number)
- Returns
Promise<void>
generateTokens(userId, data?)
Generates a new token pair and stores a hashed refresh token.
- Arguments
userId(required) —ID(string | number)data(optional) — generic payloadDto embed in access token.
- Returns
Promise<{ accessToken: string; refreshToken: string }>
sendResetPasswordEmail(email)
Creates and sends a password reset email (when email module is configured).
- Arguments
email(required) —string
- Returns
Promise<{ success: boolean; error?: unknown }>
confirmResetPassword(email, token, password)
Validates a reset token and updates the user password.
- Arguments
email(required) —stringtoken(required) —stringpassword(required) —string(new plain password, hashed internally)
- Returns
Promise<{ success: boolean; error?: unknown }>
sendConfirmPasswordEmail(email)
Creates and sends an email confirmation message.
- Arguments
email(required) —string
- Returns
Promise<{ success: boolean; error?: unknown }>
confirmEmail(email, token)
Validates the email confirmation token and marks email as confirmed via your email repo.
- Arguments
email(required) —stringtoken(required) —string
- Returns
Promise<void>
Optional email flows
To enable confirmation and reset-password flows, provide an email config.
EmailHandlerOptions API (detailed)
type EmailHandlerOptions = {
senderName: string;
senderEmail: string;
client: EmailClient;
emailConfig?: {
[TemplateTypes.CONFIRM_EMAIL]?: {
email?: Omit<Partial<SendEmailArgs>, "text" | "html" | "to">;
linkExpirationMs?: number;
};
[TemplateTypes.RESET_PASSWORD]?: {
email?: Omit<Partial<SendEmailArgs>, "text" | "html" | "to">;
linkExpirationMs?: number;
};
};
templates?: {
[TemplateTypes.CONFIRM_EMAIL]?: (params: { email: string; link: string }) => {
text: string;
html: string;
};
[TemplateTypes.RESET_PASSWORD]?: (params: { email: string; link: string }) => {
text: string;
html: string;
};
};
services: {
createResetPasswordLink(email: string, token: string): Promise<string>;
createConfirmEmailLink(email: string, token: string): Promise<string>;
};
repo: {
confirmEmail(email: string): Promise<boolean>;
resetPassword(email: string, password: string): Promise<boolean>;
};
};Email fields (required vs optional)
senderName(required) —string
Default sender display name.senderEmail(required) —string
Default sender email address (from).client(required) —EmailClient
Delivery adapter withsend(emailData: SendEmailArgs): Promise<void>.services(required) — object with async link builders:createResetPasswordLink(email, token): Promise<string>createConfirmEmailLink(email, token): Promise<string>
repo(required) — object with async persistence actions:confirmEmail(email): Promise<boolean>resetPassword(email, password): Promise<boolean>
emailConfig(optional) — per-template overrides:linkExpirationMs?: numberto customize token/link validityemail?: { senderName?: string; from?: string; subject?: string }to override metadata
templates(optional) — custom template functions per email type.- Input:
{ email: string; link: string } - Output:
{ text: string; html: string }
- Input:
Example configuration:
import { Passauth, TemplateTypes, type EmailHandlerOptions } from "passauth";
const emailOptions: EmailHandlerOptions = {
senderName: "Acme Auth",
senderEmail: "[email protected]",
client: {
async send(emailData) {
// Integrate with your provider (SES, Resend, SendGrid, etc.)
console.log("Sending email", emailData);
},
},
services: {
async createResetPasswordLink(email, token) {
return `https://app.acme.com/reset-password?email=${encodeURIComponent(email)}&token=${token}`;
},
async createConfirmEmailLink(email, token) {
return `https://app.acme.com/confirm-email?email=${encodeURIComponent(email)}&token=${token}`;
},
},
repo: {
async confirmEmail(email) {
// Mark user as emailVerified=true in your DB
return true;
},
async resetPassword(email, hashedPassword) {
// Save the hashed password in your DB
return true;
},
},
emailConfig: {
[TemplateTypes.CONFIRM_EMAIL]: {
linkExpirationMs: 1000 * 60 * 60 * 24,
email: {
subject: "Please confirm your email",
},
},
},
};Plugins
passauth supports plugins that can override or extend handler methods.
A plugin is an object with:
namehandlerInit({ passauthHandler, passauthOptions, plugins })- optional
__typeshelper for TypeScript augmentation
Minimal example:
import { Passauth, type PluginSpec, type User, type PassauthHandlerInt } from "passauth";
type HelloAPI = {
hello(): string;
};
const helloPlugin = (): PluginSpec<User, PassauthHandlerInt<User>, HelloAPI> => ({
name: "hello",
handlerInit: ({ passauthHandler }) => {
(passauthHandler as PassauthHandlerInt<User> & HelloAPI).hello = () => "hello";
},
__types: () => undefined as unknown as HelloAPI,
});
const passauth = Passauth({
secretKey: "secret",
repo,
plugins: [helloPlugin()] as const,
});
console.log(passauth.handler.hello());Error handling
All library errors extend PassauthException and include:
origin: "passauth"context: stringname: stringmessage: stringlog: string
Available PassauthExceptions
Base
PassauthException- Base class for all errors in the library.
Configuration errors
PassauthMissingConfigurationException- Thrown when required top-level config is missing (for example:
secretKey,repo).
- Thrown when required top-level config is missing (for example:
PassauthEmailMissingConfigurationException- Thrown when required email config fields are missing (for example:
senderName,senderEmail,client,services,repo).
- Thrown when required email config fields are missing (for example:
Registration/Login errors
PassauthEmailAlreadyTakenException- Thrown on
registerwhen a user with the same email already exists.
- Thrown on
PassauthInvalidUserException- Thrown on
loginwhen user is not found.
- Thrown on
PassauthBlockedUserException- Thrown on
loginwhen user is blocked (isBlocked = true).
- Thrown on
PassauthInvalidCredentialsException- Thrown on
loginwhen password does not match.
- Thrown on
PassauthEmailNotVerifiedException- Thrown on
loginwhen email features are enabled andemailVerifiedis false.
- Thrown on
Token errors
PassauthInvalidAccessTokenException- Thrown when access token verification fails (invalid/expired token).
PassauthInvalidRefreshTokenException- Thrown when refresh token is invalid, expired, missing, or revoked.
Email flow errors
PassauthEmailFailedToSendEmailException- Thrown when email send operation fails (confirmation or registration confirmation flow).
PassauthInvalidConfirmEmailTokenException- Thrown when email confirmation token is invalid or expired.
Error context values
context is one of PassauthExceptionContext values:
configregisterloginemail confirmation
Handle these exceptions in your service/controller layer and map them to your HTTP or RPC error format.
License
ISC
