He
HeliumTS
Note:

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";
4
5const client = new MongoClient(process.env.MONGODB_URI!);
6const db = client.db();
7
8export 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 against
17 // the database. This prevents the server from returning a stale session
18 // 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 up
31 },
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";
3
4// 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 directly
8 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";
2
3export async function middleware(ctx: HeliumContext) {
4 const session = await auth.api.getSession({
5 headers: ctx.req.headers,
6 });
7
8 if (!session) {
9 throw new Error("Unauthorized");
10 }
11
12 // Add session to context for use in RPC handlers
13 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";
2
3export const getProfile = defineRPC(async (ctx) => {
4 // ctx.user is available thanks to middleware
5 return {
6 id: ctx.user.id,
7 name: ctx.user.name,
8 email: ctx.user.email,
9 };
10});
11
12export const updateProfile = defineRPC(async (data: { name: string }, ctx) => {
13 // Update user profile
14 await db.users.update(ctx.user.id, { name: data.name });
15
16 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";
2
3export const { signIn, signUp, signOut, useSession, getSession } = createAuthClient();

Use in your React components:

1import { signIn, signOut, useSession } from "../libs/better-auth/auth-client";
2
3export default function LoginPage() {
4 const {
5 data: session,
6 isPending, // loading state
7 refetch,
8 } = useSession();
9
10 const handleGoogleLogin = async () => {
11 await signIn.social({
12 provider: "google",
13 callbackURL: "/dashboard",
14 });
15 };
16
17 if (isPending) {
18 return <div>Loading...</div>;
19 }
20
21 if (session) {
22 return (
23 <div>
24 <p>Welcome, {session.user.name}!</p>
25 <button onClick={() => signOut()}>Sign Out</button>
26 </div>
27 );
28 }
29
30 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 config
3
4export 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";
3
4export const clerkWebhook = defineHTTPRequest("POST", "/webhooks/clerk", async (req, ctx) => {
5 const webRequest = await req.toWebRequest();
6 // Handle Clerk webhooks
7 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