How is Authentication Handled in TREK: JWT, OAuth, and Passkeys Explained
TREK uses a layered authentication strategy that combines JWT session tokens stored in HttpOnly cookies, OAuth/OpenID Connect for external identity providers, and WebAuthn Passkeys for passwordless authentication.
The open-source TREK repository (mauriceboe/TREK) implements a modern, security-focused authentication system in its Node.js/TypeScript backend. By combining three distinct mechanisms—stateless JWT sessions, OAuth federation, and cryptographic Passkeys—the application provides flexible, phishing-resistant login options while maintaining strict session security through hardened cookie policies and middleware-based verification.
JWT Session Tokens
TREK relies on signed JWTs for stateless session management. Rather than storing session data server-side, the backend issues compact tokens that carry user identity and expire automatically.
Token Generation in the OIDC Service
In server/src/services/oidcService.ts, the generateToken function creates signed JWTs using the jsonwebtoken library. When a user successfully authenticates via OAuth or Passkeys, the system calls jwt.sign() with a HS256 algorithm and a 5-minute expiration:
import jwt from 'jsonwebtoken';
import { JWT_SECRET } from '@/config';
const jwtPayload = { id: userId, purpose: 'auth' };
const jwtToken = jwt.sign(jwtPayload, JWT_SECRET, {
algorithm: 'HS256',
expiresIn: '5m',
});
The JWT_SECRET is loaded from environment variables (see server/.env.example) and should be rotated regularly according to the guidelines in wiki/Encryption-Key-Rotation.md.
Verification in the Auth Middleware
Every protected route passes through the global auth middleware located in server/src/middleware/auth.ts. This middleware extracts the trek_session cookie, verifies the signature using jwt.verify(), and attaches the decoded user object to req.user:
import jwt from 'jsonwebtoken';
import { JWT_SECRET } from '@/config';
export function authMiddleware(req, res, next) {
const token = req.cookies?.trek_session;
if (!token) return res.status(401).send('Missing auth cookie');
try {
const payload = jwt.verify(token, JWT_SECRET);
req.user = { id: payload.id };
next();
} catch (err) {
return res.status(401).send('Invalid or expired token');
}
}
If verification fails, the middleware returns a 401 status immediately, preventing unauthenticated access to downstream resources.
OAuth and OpenID Connect
For users preferring external identity providers, TREK implements the OAuth 2.0 authorization code flow with OpenID Connect extensions.
Authorization Code Flow
When a user initiates login, the frontend redirects to /api/auth/oidc/login, which triggers the OIDC handshake. The server/src/services/oidcService.ts file handles the provider redirection, while server/src/services/oauthService.ts contains helper functions for client-secret management and scope definition.
Token Exchange and JWT Creation
After the user authenticates with a provider like Google or Microsoft, the OIDC controller receives the authorization code and exchanges it for an ID token. The service extracts the subject identifier (sub), generates a TREK-specific JWT, and calls setAuthCookie to establish the session:
export async function oidcCallback(req, res) {
const { code } = req.body;
const tokenInfo = await oidcProvider.exchangeCodeForToken(code);
const jwtPayload = { id: tokenInfo.sub, purpose: 'auth' };
const jwtToken = jwt.sign(jwtPayload, JWT_SECRET, {
algorithm: 'HS256',
expiresIn: '5m',
});
setAuthCookie(res, jwtToken, req);
res.json({ token: jwtToken });
}
Client-side invocation requires the credentials: 'include' flag to ensure the HttpOnly cookie is transmitted:
await fetch('/api/auth/oidc/login', {
method: 'POST',
credentials: 'include',
});
Passkeys and WebAuthn
TREK supports FIDO2/WebAuthn Passkeys for passwordless, phishing-resistant authentication using public-key cryptography stored on user devices.
Registration and Validation
The server/src/services/passkeyService.ts file manages credential registration and assertion verification. When a user opts for Passkey login, the frontend uses the WebAuthn API to generate a cryptographic signature:
const credential = await navigator.credentials.get({ publicKey: options });
await fetch('/api/auth/passkey/login', {
method: 'POST',
body: JSON.stringify(credential),
credentials: 'include',
});
JWT Integration for Passkey Sessions
Upon receiving the assertion, the Passkey service validates the signature using verifyWebAuthnAssertion(), then issues a standard JWT identical to the OAuth flow. This design ensures that Passkey sessions integrate seamlessly with the existing cookie-based session infrastructure:
import { verifyWebAuthnAssertion } from '@/utils/webauthn';
export async function passkeyLogin(req, res) {
const assertion = req.body;
const user = await verifyWebAuthnAssertion(assertion);
const jwtToken = jwt.sign({ id: user.id, purpose: 'auth' }, JWT_SECRET, {
algorithm: 'HS256',
expiresIn: '5m',
});
setAuthCookie(res, jwtToken, req);
res.json({ token: jwtToken });
}
Security Configuration and Cookie Hardening
TREK enforces strict transport security through cookie flags and additional MFA policies.
HttpOnly and SameSite Policies
The setAuthCookie implementation (called from both OIDC and Passkey controllers) configures the trek_session cookie with HttpOnly, SameSite=Strict, and Secure attributes. This prevents XSS attacks and CSRF vectors while ensuring the token only transmits over HTTPS.
Multi-Factor Enforcement
After initial authentication, the mfaPolicy middleware in server/src/middleware/mfaPolicy.ts may require additional verification before granting full resource access. This operates as a secondary layer after the JWT middleware, checking whether the authenticated user has satisfied MFA requirements based on policy rules.
Summary
- JWT-based sessions provide stateless, signed tokens (HS256 algorithm, 5-minute expiry) stored in HttpOnly cookies named
trek_session. - OAuth/OpenID Connect integration in
server/src/services/oidcService.tssupports external identity providers via the authorization code flow, converting provider tokens into TREK-session JWTs. - Passkey authentication via
server/src/services/passkeyService.tsenables passwordless login using WebAuthn, reusing the same JWT cookie infrastructure for session continuity. - Security hardening includes
SameSite=Strictcookies, MFA policy enforcement inserver/src/middleware/mfaPolicy.ts, and documented JWT secret rotation procedures.
Frequently Asked Questions
What token format does TREK use for sessions?
TREK uses signed JWTs (JSON Web Tokens) with the HS256 algorithm. The tokens contain a user ID and purpose claim (auth), expire after 5 minutes, and are stored in an HttpOnly cookie named trek_session. The global auth middleware verifies these tokens on every request using the JWT_SECRET defined in server/src/config.ts.
How does TREK handle OAuth providers like Google?
TREK implements the OAuth 2.0 authorization code flow with OpenID Connect. The server/src/services/oidcService.ts file handles the exchange of authorization codes for ID tokens, extracts the user identity from the provider's response, and generates a TREK-specific JWT. This allows seamless integration with Google, Microsoft, and other OIDC-compliant providers without storing provider credentials locally.
Are Passkeys supported for passwordless login?
Yes. TREK fully supports FIDO2/WebAuthn Passkeys through server/src/services/passkeyService.ts. Users can register public-key credentials on their devices and authenticate without passwords. The service validates WebAuthn assertions cryptographically, then issues a standard JWT that flows through the same cookie-based session system as OAuth logins, ensuring consistent security policies across all authentication methods.
How can I rotate the JWT secret without logging users out?
The repository includes a dedicated wiki page at wiki/Encryption-Key-Rotation.md that describes safe rotation procedures for JWT_SECRET. Because TREK uses stateless JWTs stored in cookies, rotating the secret requires careful timing—typically issuing tokens with a new secret while maintaining verification capabilities for the old secret during a transition window—to prevent immediate session termination for active users.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →