Skip to content
Merged
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
7 changes: 7 additions & 0 deletions .changeset/seamless-service-token-env.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@seamless-auth/express": patch
"@seamless-auth/fastify": patch
"@seamless-auth/nextjs": patch
---

The README examples read the service secret from `SEAMLESS_SERVICE_TOKEN` instead of `SERVICE_SECRET`. The auth server still reads `API_SERVICE_TOKEN`; both hold the same value. The adapters read no environment variables, so nothing changes at runtime.
14 changes: 8 additions & 6 deletions packages/express/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ app.use(
createSeamlessAuthServer({
authServerUrl: process.env.AUTH_SERVER_URL!,
cookieSecret: process.env.COOKIE_SECRET!,
serviceSecret: process.env.SERVICE_SECRET!,
serviceSecret: process.env.SEAMLESS_SERVICE_TOKEN!,
audience: process.env.AUTH_SERVER_URL!,
}),
);
Expand Down Expand Up @@ -317,7 +317,7 @@ app.use(
createSeamlessAuthServer({
authServerUrl: "https://identifier.seamlessauth.com",
cookieSecret: process.env.COOKIE_SECRET,
serviceSecret: process.env.SERVICE_SECRET,
serviceSecret: process.env.SEAMLESS_SERVICE_TOKEN,
audience: "https://identifier.seamlessauth.com",
// local HTTP dev only, never in a deployed environment
cookieSecure: false,
Expand Down Expand Up @@ -356,7 +356,7 @@ app.use(
createSeamlessAuthServer({
authServerUrl: "https://identifier.seamlessauth.com",
cookieSecret: process.env.COOKIE_SECRET,
serviceSecret: process.env.SERVICE_SECRET,
serviceSecret: process.env.SEAMLESS_SERVICE_TOKEN,
audience: "https://identifier.seamlessauth.com",
allowedOrigins: ["https://app.example.com"],
}),
Expand All @@ -375,6 +375,8 @@ This currently applies to:

External delivery is a credentialed request. The adapter mints a short-lived service token from `serviceSecret`, and the auth server withholds the delivery payload if that token does not validate. `serviceSecret` must therefore match the auth server's `API_SERVICE_TOKEN` in every environment, including local development. If it does not, auth-message routes still return a success response but no message is delivered, so the adapter logs a warning whenever it requests external delivery and receives no payload back.

The auth server reads the secret from `API_SERVICE_TOKEN`, and the examples here read it in the app from `SEAMLESS_SERVICE_TOKEN`; both hold the same value.

---

### `createSeamlessConsoleProxy(options)`
Expand Down Expand Up @@ -660,7 +662,7 @@ options once and reuse them.
const authOptions = {
authServerUrl: process.env.AUTH_SERVER_URL!,
cookieSecret: process.env.COOKIE_SECRET!,
serviceSecret: process.env.SERVICE_SECRET!,
serviceSecret: process.env.SEAMLESS_SERVICE_TOKEN!,
audience: process.env.AUTH_AUDIENCE!,
};

Expand Down Expand Up @@ -740,7 +742,7 @@ whatever your app already uses and pass the values through as options:
```bash
AUTH_SERVER_URL=http://localhost:5312
COOKIE_SECRET=local-dev-cookie-secret-at-least-32-chars
SERVICE_SECRET=local-dev-service-secret-at-least-32-chars
SEAMLESS_SERVICE_TOKEN=local-dev-service-token-at-least-32-chars
```

```ts
Expand All @@ -749,7 +751,7 @@ app.use(
createSeamlessAuthServer({
authServerUrl: process.env.AUTH_SERVER_URL!,
cookieSecret: process.env.COOKIE_SECRET!,
serviceSecret: process.env.SERVICE_SECRET!,
serviceSecret: process.env.SEAMLESS_SERVICE_TOKEN!,
audience: process.env.AUTH_SERVER_URL!,
// local HTTP only, never in a deployed environment
cookieSecure: false,
Expand Down
6 changes: 4 additions & 2 deletions packages/fastify/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ await app.register(seamlessAuth, {
authServerUrl: "https://identifier.seamlessauth.com",
audience: "https://identifier.seamlessauth.com",
cookieSecret: process.env.COOKIE_SECRET!,
serviceSecret: process.env.SERVICE_SECRET!,
serviceSecret: process.env.SEAMLESS_SERVICE_TOKEN!,
jwksKid: "2024-09-main",
});

Expand All @@ -43,7 +43,9 @@ hooks scoped to those routes, so the rest of your application is untouched.
`@fastify/cookie` is registered for you inside the plugin.

`cookieSecret` and `serviceSecret` must be at least 32 characters and the
`serviceSecret` must match the auth API's. Both are checked at registration, so a
`serviceSecret` must match the auth API's. The auth server reads it from
`API_SERVICE_TOKEN` and the app from `SEAMLESS_SERVICE_TOKEN`, with the same value.
Both are checked at registration, so a
weak secret fails at startup rather than on the first request.

## Guarding your own routes
Expand Down
8 changes: 5 additions & 3 deletions packages/nextjs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const { GET, POST, PUT, PATCH, DELETE } = createSeamlessAuthHandler({
authServerUrl: process.env.AUTH_SERVER_URL!,
audience: process.env.AUTH_SERVER_URL!,
cookieSecret: process.env.COOKIE_SECRET!,
serviceSecret: process.env.SERVICE_SECRET!,
serviceSecret: process.env.SEAMLESS_SERVICE_TOKEN!,
jwksKid: process.env.JWKS_KID,
});
```
Expand All @@ -44,7 +44,9 @@ origin:
```

`cookieSecret` and `serviceSecret` must be at least 32 characters and the
`serviceSecret` must match the auth API's. Both are checked when the handler is
`serviceSecret` must match the auth API's. The auth server reads it from
`API_SERVICE_TOKEN` and the app from `SEAMLESS_SERVICE_TOKEN`, with the same value.
Both are checked when the handler is
created, so a weak secret fails at startup rather than on the first request.

The adapter signs cookies with `jsonwebtoken`, so the route needs the Node.js
Expand All @@ -62,7 +64,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
const session = await getSeamlessSession(await cookies(), {
authServerUrl: process.env.AUTH_SERVER_URL!,
cookieSecret: process.env.COOKIE_SECRET!,
serviceSecret: process.env.SERVICE_SECRET!,
serviceSecret: process.env.SEAMLESS_SERVICE_TOKEN!,
jwksKid: process.env.JWKS_KID,
userAgent: (await headers()).get("user-agent") ?? undefined,
});
Expand Down
Loading