Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
343 changes: 190 additions & 153 deletions examples/ask-the-documents/package-lock.json

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions examples/auth-providers/better-auth/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 15 additions & 23 deletions examples/auth-providers/better-auth/src/auth/provider.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { fromNodeHeaders } from "better-auth/node";
import type { Request as ExpressRequest } from "express";
import type {
AuthProvider,
VerifiedSession,
Expand All @@ -10,7 +8,7 @@ import { auth } from "./betterAuth";
/**
* Better Auth, expressed as a Wasp `AuthProvider`.
*
* The whole adapter is three methods, and only the first one does real work.
* The whole adapter is two methods, and only the first one does real work.
* Everything Wasp builds on top of it -- `context.user`, `authRequired` pages,
* `auth: true` operations, `useAuth()`, websocket auth -- comes for free.
*
Expand All @@ -27,33 +25,27 @@ export const betterAuthProvider: AuthProvider = {
*/
id: "better-auth",

async verifyRequest(req: ExpressRequest): Promise<VerifiedSession | null> {
const session = await auth.api.getSession({
headers: fromNodeHeaders(req.headers),
});

if (!session) {
return null;
}

return { sessionId: session.session.id, subjectId: session.user.id };
},

/**
* Websockets hand Wasp a bare token rather than a request, so the adapter has
* to be able to verify one out of context. Better Auth reads the bearer token
* from an `Authorization` header, so we synthesise the header it expects.
* Wasp hands every adapter a standard web `Request` -- built from the HTTP
* request, or synthesized with just an `Authorization` header for websocket
* auth. Better Auth consumes its headers directly either way.
*/
async verifyCredential(credential: string): Promise<VerifiedSession | null> {
const session = await auth.api.getSession({
headers: new Headers({ authorization: `Bearer ${credential}` }),
});
async authenticate(request: Request): Promise<VerifiedSession | null> {
const session = await auth.api.getSession({ headers: request.headers });

if (!session) {
return null;
}

return { sessionId: session.session.id, subjectId: session.user.id };
return {
sessionId: session.session.id,
subjectId: session.user.id,
// Verified profile data Wasp records when it provisions the local user.
claims: {
email: session.user.email,
name: session.user.name,
},
};
},

async revokeSession(sessionId: string): Promise<void> {
Expand Down
16 changes: 16 additions & 0 deletions examples/auth-providers/clerk/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

69 changes: 20 additions & 49 deletions examples/auth-providers/clerk/src/auth/provider.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { createClerkClient } from "@clerk/backend";
import type { Request as ExpressRequest } from "express";
import type {
AuthProvider,
VerifiedSession,
Expand Down Expand Up @@ -32,36 +31,18 @@ export const clerkAuthProvider: AuthProvider = {
*/
id: "clerk",

async verifyRequest(req: ExpressRequest): Promise<VerifiedSession | null> {
// Clerk reads either its `__session` cookie or an `Authorization: Bearer`
// header transparently, so the same code serves web and native clients.
//
// With `jwtKey` set this is local RS256 verification with no network call;
// without it, Clerk fetches (and caches) the JWKS.
const requestState = await clerk.authenticateRequest(toWebRequest(req), {
jwtKey: process.env.CLERK_JWT_KEY,
});

if (!requestState.isAuthenticated) {
return null;
}

const { userId, sessionId } = requestState.toAuth();
if (!userId || !sessionId) {
return null;
}

return { sessionId, subjectId: userId };
},

/**
* Websockets hand Wasp a bare token, so we rebuild the request Clerk expects.
* Wasp hands every adapter a standard web `Request` -- built from the HTTP
* request, or synthesized with just an `Authorization` header for websocket
* auth. Clerk's SDK consumes one natively, so there is nothing to convert.
*
* Clerk reads either its `__session` cookie or an `Authorization: Bearer`
* header transparently, so the same code serves web and native clients.
*
* With `jwtKey` set this is local RS256 verification with no network call;
* without it, Clerk fetches (and caches) the JWKS.
*/
async verifyCredential(credential: string): Promise<VerifiedSession | null> {
const request = new Request("http://localhost/", {
headers: { authorization: `Bearer ${credential}` },
});

async authenticate(request: Request): Promise<VerifiedSession | null> {
const requestState = await clerk.authenticateRequest(request, {
jwtKey: process.env.CLERK_JWT_KEY,
});
Expand All @@ -70,12 +51,20 @@ export const clerkAuthProvider: AuthProvider = {
return null;
}

const { userId, sessionId } = requestState.toAuth();
const { userId, sessionId, sessionClaims } = requestState.toAuth();
if (!userId || !sessionId) {
return null;
}

return { sessionId, subjectId: userId };
return {
sessionId,
subjectId: userId,
// The verified JWT's claims, recorded by Wasp when it provisions the
// local user. NOTE: Clerk's default session token carries no email --
// add one to the token template in the Clerk dashboard if the app's
// user entity needs it at provisioning time.
claims: sessionClaims as VerifiedSession["claims"],
};
},

/**
Expand All @@ -91,21 +80,3 @@ export const clerkAuthProvider: AuthProvider = {
await clerk.sessions.revokeSession(sessionId);
},
};

/** Express gives us a Node request; Clerk's SDK wants a web `Request`. */
function toWebRequest(req: ExpressRequest): Request {
const headers = new Headers();
for (const [key, value] of Object.entries(req.headers)) {
if (typeof value === "string") {
headers.set(key, value);
} else if (Array.isArray(value)) {
headers.set(key, value.join(", "));
}
}

const host = req.get("host") ?? "localhost";
return new Request(`${req.protocol}://${host}${req.originalUrl}`, {
method: req.method,
headers,
});
}
16 changes: 16 additions & 0 deletions examples/auth-providers/wasp-auth/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading