This Node.js SDK provides seamless integration with an Authula server for both client-side and server-side applications and is framework agnostic.
- Framework Agnostic: Works with Next.js/React, Vue.js and more
- Full TypeScript Support: Complete TypeScript definitions with strict typing
- SSR Safe: Supports proper cookie handling for SSR apps
- CSRF Protection: Automatic CSRF token handling for mutating requests
- Multiple Auth Methods: Email/password, OAuth2, JWT-based authentication
- Plugin Architecture: Extensible plugin system for custom authentication flows
- Automatic Token Refresh: Built-in bearer token refresh mechanism
npm install authula
# or
yarn add authula
# or
pnpm add authulaimport { createClient } from "authula";
import { EmailPasswordPlugin } from "authula/plugins";
// Create a client instance
const authulaClient = createClient({
// Your Authula server URL
url: "http://localhost:8080/auth",
plugins: [new EmailPasswordPlugin()],
});
// Now you can use the client to perform authentication operationsFor server-side rendering or applications that need to handle cookies properly:
import { cookies } from "next/headers";
import { createClient } from "authula";
import { EmailPasswordPlugin, CSRFPlugin } from "authula/plugins";
const authulaClient = createClient({
url: "http://localhost:8080/auth",
cookies: cookies, // Provide cookie store for SSR
plugins: [
new EmailPasswordPlugin(),
new CSRFPlugin({
cookieName: "authula_csrf_token",
headerName: "X-AUTHULA-CSRF-TOKEN",
}),
],
});The client provides built-in methods for essential authentication operations:
Retrieve information about the currently authenticated user:
const { user, session } = await authulaClient.getMe();
console.log(user.email);
console.log(session.id);Sign out the current user or all sessions:
// Sign out current session
await authulaClient.signOut({});
// Sign out all sessions
await authulaClient.signOut({
signOutAll: true,
});
// Sign out a specific session
await authulaClient.signOut({
sessionId: "session-id",
});Access a plugin instance programmatically:
const emailPasswordPlugin = authulaClient.getPlugin("emailPassword");
// Use the plugin
if (emailPasswordPlugin) {
// Plugin methods are now available
}Provides role-based access control (RBAC) management for users, including roles, permissions, and their assignments.
import { AccessControlPlugin } from "authula/plugins";
const authulaClient = createClient({
url: "http://localhost:8080/auth",
plugins: [new AccessControlPlugin()],
});// Create a new role
await authulaClient.accessControl.createRole({
name: "Admin",
description: "Administrator role",
isSystem: false,
});
// Get all roles
const allRoles = await authulaClient.accessControl.getAllRoles();
// Get a specific role
const role = await authulaClient.accessControl.getRoleById("role-id");
// Update a role
await authulaClient.accessControl.updateRole("role-id", {
name: "Updated name",
description: "Updated description",
});
// Delete a role
await authulaClient.accessControl.deleteRole("role-id");// Create a new permission
await authulaClient.accessControl.createPermission({
key: "users.create",
description: "Create new users",
isSystem: false,
});
// Get all permissions
const allPermissions = await authulaClient.accessControl.getAllPermissions();
// Update a permission
await authulaClient.accessControl.updatePermission("permission-id", {
description: "Updated permission description",
});
// Delete a permission
await authulaClient.accessControl.deletePermission("permission-id");// Add a permission to a role
await authulaClient.accessControl.addRolePermission("role-id", {
permissionId: "permission-id",
});
// Get all permissions for a role
const rolePermissions = await authulaClient.accessControl.getRolePermissions(
"role-id",
);
// Replace all permissions for a role
await authulaClient.accessControl.replaceRolePermissions("role-id", {
permissionIds: ["permission-id-1", "permission-id-2", "permission-id-3"],
});
// Remove a permission from a role
await authulaClient.accessControl.removeRolePermission(
"role-id",
"permission-id",
);// Get all roles assigned to a user
const userRoles = await authulaClient.accessControl.getUserRoles("user-id");
// Assign a role to a user
await authulaClient.accessControl.assignUserRole("user-id", {
roleId: "role-id",
expiresAt: new Date("2025-12-31"), // Optional: role expiration date
});
// Replace all roles for a user
await authulaClient.accessControl.replaceUserRoles("user-id", {
roleIds: ["role-id-1", "role-id-2"],
});
// Remove a role from a user
await authulaClient.accessControl.removeUserRole("user-id", "role-id");// Get all effective permissions for a user (from all assigned roles)
const userPermissions = await authulaClient.accessControl.getUserEffectivePermissions("user-id");Provides the ability to manage users, accounts, sessions, and impersonations.
import { AdminPlugin } from "authula/plugins";
const authulaClient = createClient({
url: "http://localhost:8080/auth",
plugins: [new AdminPlugin()],
});await authulaClient.admin.createUser({
name: "John Doe",
email: "user@example.com",
// other fields...
});
// Get all users with pagination
const users = await authulaClient.admin.getAllUsers(100);
// Get a specific user by ID
const user = await authulaClient.admin.getUserById("user-id");
// Update user information
await authulaClient.admin.updateUser("user-id", { name: "Jane" });
// Delete a user
await authulaClient.admin.deleteUser("user-id");// Create a new account for a user
await authulaClient.admin.createAccount("user-id", { /* account data */ });
// Get all accounts for a user
await authulaClient.admin.getUserAccounts("user-id");
// Get a specific account by ID
await authulaClient.admin.getAccountById("account-id");
// Update account information
await authulaClient.admin.updateAccount("account-id", { /* data */ });
// Delete an account
await authulaClient.admin.deleteAccount("account-id");// Get user state
await authulaClient.admin.getUserState("user-id");
// Create or update user state
await authulaClient.admin.createUserState("user-id", { /* state data */ });
// Update user state
await authulaClient.admin.updateUserState("user-id", { /* state data */ });
// Delete user state
await authulaClient.admin.deleteUserState("user-id");
// Get all banned user states
await authulaClient.admin.getBannedUserStates();
// Ban a user
await authulaClient.admin.banUser("user-id", { reason: "reason..." });
// Unban a user
await authulaClient.admin.unbanUser("user-id");
// Get all active sessions for a user
await authulaClient.admin.getUserAdminSessions("user-id");// Get session state
await authulaClient.admin.getSessionState("session-id");
// Create or update session state
await authulaClient.admin.createSessionState("session-id", { /* data */ });
// Update session state
await authulaClient.admin.updateSessionState("session-id", { /* data */ });
// Delete session state
await authulaClient.admin.deleteSessionState("session-id");
// Get all revoked session states
await authulaClient.admin.getRevokedSessionStates();
// Revoke a session
await authulaClient.admin.revokeSession("session-id", { reason: "reason..." });// Get all active impersonations
await authulaClient.admin.getAllImpersonations();
// Get a specific impersonation by ID
await authulaClient.admin.getImpersonationById("impersonation-id");
// Start impersonating a user
await authulaClient.admin.startImpersonation({ user_id: "user-id", /* data */ });
// Stop impersonation
await authulaClient.admin.stopImpersonation("impersonation-id");Handles traditional email/password authentication flows.
import { EmailPasswordPlugin } from "authula/plugins";
const authulaClient = createClient({
url: "http://localhost:8080/auth",
plugins: [new EmailPasswordPlugin()],
});
// Sign up
await authulaClient.emailPassword.signUp({
name: "John Doe",
email: "john@example.com",
password: "securePassword123",
callbackUrl: "http://localhost:3000/callback", // Optional callback URL
});
// Sign in
const response = await authulaClient.emailPassword.signIn({
email: "john@example.com",
password: "securePassword123",
callbackUrl: "http://localhost:3000/callback", // Optional callback URL
});
// Send email verification
await authulaClient.emailPassword.sendEmailVerification({
email: "john@example.com",
callbackUrl: "http://localhost:3000/callback", // Optional callback URL
});
// Request password reset
await authulaClient.emailPassword.requestPasswordReset({
email: "john@example.com",
callbackUrl: "http://localhost:3000/callback", // Optional callback URL
});
// Change password
await authulaClient.emailPassword.changePassword({
token: "reset-token",
password: "newSecurePassword123",
});
// Request email change
await authulaClient.emailPassword.requestEmailChange({
email: "john.doe@example.com",
callbackUrl: "http://localhost:3000/callback", // Optional callback URL
});Handles OAuth2 authentication with popular providers.
import { OAuth2Plugin } from "authula/plugins";
const authulaClient = createClient({
url: "http://localhost:8080/auth",
plugins: [new OAuth2Plugin()],
});
// Redirect user to OAuth2 provider
const response = await authulaClient.oauth2.signIn({
provider: "google", // or "github", "discord"
redirect_to: "http://localhost:3000/callback",
});
// Redirect user to the authUrl
window.location.href = response.auth_url;Provides automatic CSRF protection for mutating requests.
import { CSRFPlugin } from "authula/plugins";
const authulaClient = createClient({
url: "http://localhost:8080/auth",
cookies: ..., // Provide cookie store for SSR if needed, else omit for SPA/Mobile apps
plugins: [
new CSRFPlugin({
cookieName: "csrf_token", // Name of the CSRF token cookie
headerName: "X-CSRF-TOKEN" // Header name to send the token
})
]
});
// CSRF tokens will be automatically added to mutating requests (POST, PUT, PATCH, DELETE)Handles JWT token operations including refresh.
import { JWTPlugin } from "authula/plugins";
const authulaClient = createClient({
url: "http://localhost:8080/auth",
plugins: [new JWTPlugin()],
});
// Refresh JWT tokens
const tokens = await authulaClient.jwt.refreshToken({
refresh_token: "your-refresh-token",
});
// Get JWKS keys
const jwksKeys = await authulaClient.jwt.getJWKSKeys();Provides automatic bearer token handling and refresh.
import { BearerPlugin, JWTPlugin } from "authula/plugins";
const authulaClient = createClient({
url: "http://localhost:8080/auth",
plugins: [
new JWTPlugin(),
new BearerPlugin({
headerName: "Authorization", // Can be omitted as default is Authorization
}),
],
});
// The Bearer plugin will automatically:
// 1. Add Authorization: Bearer <token> header to requests
// 2. Handle token refresh when receiving 401 responses
// 3. Store tokens in localStorage (access_token and refresh_token)Provides flows for passwordless authentication.
import { MagicLinkPlugin } from "authula/plugins";
const authulaClient = createClient({
url: "http://localhost:8080/auth",
plugins: [new MagicLinkPlugin()],
});
// Send magic link via email
await authulaClient.magicLink.signIn({
email: "john.doe@example.com",
name: "John Doe", // Optional name
callbackUrl: "http://localhost:3000/callback", // Optional callback URL
});
// Verify magic link token
await authulaClient.magicLink.verify({
token: "magic-link-token",
callbackUrl: "http://localhost:3000/callback", // Optional callback URL
});
// Exchange token from verify endpoint for session
await authulaClient.magicLink.exchange({
token: "magic-link-token",
});Configure fetch behavior with timeout and other options:
const authulaClient = createClient({
url: "http://localhost:8080/auth",
fetchOptions: {
abortTimeout: 30, // Timeout in seconds
},
plugins: [
// your plugins
],
});Add custom before/after fetch hooks for advanced customization:
const authulaClient = createClient({
url: "http://localhost:8080/auth",
plugins: [new EmailPasswordPlugin()],
});
// Register a before fetch hook
authulaClient.registerBeforeFetch(async (ctx) => {
console.log(`Making request to: ${ctx.url}`);
// Modify context if needed
ctx.init.headers = {
...ctx.init.headers,
"X-Custom-Header": "value",
};
});
// Register an after fetch hook
authulaClient.registerAfterFetch(async (ctx, response) => {
console.log(`Received response: ${response.status}`);
if (response.status >= 400) {
// Handle error
}
});{
// Base URL of your Authula server
url: string,
// Optional fetch configuration
fetchOptions?: {
// Request timeout in seconds
abortTimeout?: number
},
// Cookie provider for SSR compatibility
cookies?: () => CookieStore
}All methods return promises that can be caught for error handling:
try {
const response = await authulaClient.emailPassword.signIn({
email: "user@example.com",
password: "password",
});
console.log("Signed in successfully", response);
} catch (error) {
console.error("Sign in failed:", error);
}Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
This project is licensed under the Apache 2.0 License - see the LICENSE file for details.
