HeliumTS is under pre-beta and active development. Expect bugs and breaking changes. If you find any issues, please report them in our GitHub
A stable release is planned for early December 2025.
Authentication
This guide shows how to integrate authentication with HeliumTS using Better Auth. The same pattern works for other auth libraries like Auth.js, Clerk, or any provider that uses standard Web API Request/Response objects.
Better Auth Example
Better Auth is a modern authentication library with excellent TypeScript support.
Installation
%npm install better-auth
Setup Auth Configuration
Create your auth configuration file:
src/libs/better-auth/auth.ts
1import { betterAuth } from "better-auth";2import { mongodbAdapter } from "better-auth/adapters/mongodb";3import { MongoClient } from "mongodb";45const client = new MongoClient(process.env.MONGODB_URI!);6const db = client.db();78export const auth = betterAuth({9 database: mongodbAdapter(db, {10 // Optional: if you don't provide a client, database transactions won't be enabled.11 client,12 }),13 experimental: {14 joins: true,15 },16 // Disable the cookie cache so server always validates session state against17 // the database. This prevents the server from returning a stale session18 // when the DB session was manually deleted or revoked elsewhere.19 session: {20 cookieCache: {21 enabled: false,22 strategy: "jwt",23 maxAge: 300,24 },25 },26 socialProviders: {27 google: {28 clientId: process.env.GOOGLE_CLIENT_ID!,29 clientSecret: process.env.GOOGLE_CLIENT_SECRET!,30 disableSignUp: true, // Disable this if you want to allow new users to sign up31 },32 },33});
Create Auth Handler
Use a catch-all route to handle all auth endpoints:
src/server/auth.ts
1import { defineHTTPRequest } from "heliumts/server";2import { auth } from "../libs/better-auth/auth";34// This handles all auth routes: /api/auth/signin, /api/auth/signout,5// /api/auth/callback/google, etc.6export const betterAuthHttp = defineHTTPRequest("ALL", "/api/auth/*", async (req, _ctx) => {7 // Call the better-auth handler directly8 return auth.handler(await req.toWebRequest());9});
Protecting RPC Endpoints
Add authentication check in your global middleware:
src/server/_middleware.ts
1import { auth } from "../libs/better-auth/auth";23export async function middleware(ctx: HeliumContext) {4 const session = await auth.api.getSession({5 headers: ctx.req.headers,6 });78 if (!session) {9 throw new Error("Unauthorized");10 }1112 // Add session to context for use in RPC handlers13 return {14 ...ctx,15 session,16 user: session.user,17 };18}
Now your RPC functions automatically have access to the authenticated user:
1import { defineRPC } from "heliumts/server";23export const getProfile = defineRPC(async (ctx) => {4 // ctx.user is available thanks to middleware5 return {6 id: ctx.user.id,7 name: ctx.user.name,8 email: ctx.user.email,9 };10});1112export const updateProfile = defineRPC(async (data: { name: string }, ctx) => {13 // Update user profile14 await db.users.update(ctx.user.id, { name: data.name });1516 return { success: true };17});
Client-Side Usage
Create a client instance with React hooks:
src/libs/better-auth/auth-client.ts
1import { createAuthClient } from "better-auth/react";23export const { signIn, signUp, signOut, useSession, getSession } = createAuthClient();
Use in your React components:
1import { signIn, signOut, useSession } from "../libs/better-auth/auth-client";23export default function LoginPage() {4 const {5 data: session,6 isPending, // loading state7 refetch,8 } = useSession();910 const handleGoogleLogin = async () => {11 await signIn.social({12 provider: "google",13 callbackURL: "/dashboard",14 });15 };1617 if (isPending) {18 return <div>Loading...</div>;19 }2021 if (session) {22 return (23 <div>24 <p>Welcome, {session.user.name}!</p>25 <button onClick={() => signOut()}>Sign Out</button>26 </div>27 );28 }2930 return (31 <div>32 <button onClick={handleGoogleLogin}>Sign In with Google</button>33 </div>34 );35}
Using Other Auth Libraries
The same pattern works for any auth library that uses standard Web API Request/Response:
Auth.js (NextAuth)
1import { defineHTTPRequest } from "heliumts/server";2import { handlers } from "./auth"; // Your Auth.js config34export const authHandler = defineHTTPRequest("ALL", "/api/auth/*", async (req, ctx) => {5 const webRequest = await req.toWebRequest();6 return handlers(webRequest);7});
Clerk
1import { defineHTTPRequest } from "heliumts/server";2import { clerkClient } from "@clerk/clerk-sdk-node";34export const clerkWebhook = defineHTTPRequest("POST", "/webhooks/clerk", async (req, ctx) => {5 const webRequest = await req.toWebRequest();6 // Handle Clerk webhooks7 return new Response(JSON.stringify({ received: true }), {8 status: 200,9 headers: { "Content-Type": "application/json" },10 });11});
Best Practices
- Always use HTTPS in production
- Store sensitive credentials in environment variables
- Implement rate limiting on auth endpoints
- Use secure session storage (httpOnly cookies)
- Validate and sanitize all user input
- Implement proper password requirements
- Add CSRF protection for sensitive actions
- Log authentication events for security monitoring
- Use middleware consistently across protected endpoints