@pikku/cli 0.12.24 → 0.12.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.schema.json +1 -1
- package/console-app/assets/index-D4DgafuS.js +232 -0
- package/console-app/index.html +1 -1
- package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-channel.js +16 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.json +41 -0
- package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
- package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.json +163 -99
- package/dist/.pikku/function/pikku-functions.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-wirings-meta.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-wirings.gen.js +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
- package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
- package/dist/.pikku/pikku-meta-service.gen.js +1 -1
- package/dist/.pikku/pikku-services.gen.d.ts +3 -1
- package/dist/.pikku/pikku-services.gen.js +2 -0
- package/dist/.pikku/pikku-types.gen.d.ts +1 -1
- package/dist/.pikku/pikku-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +17 -14
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
- package/dist/.pikku/schemas/register.gen.js +15 -5
- package/dist/.pikku/schemas/schemas/PikkuCLIConfig.schema.json +1 -1
- package/dist/.pikku/schemas/schemas/PikkuEmailsOutput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/PikkuFunctionTypesSplitInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/PikkuTriggerTypesInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/WorkspaceValidateInput.schema.json +1 -0
- package/dist/.pikku/schemas/schemas/WorkspaceValidateOutput.schema.json +1 -0
- package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
- package/dist/.pikku/workflow/meta/allWorkflow.gen.json +5 -5
- package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
- package/dist/bin/pikku-bin.mjs +2 -2
- package/dist/src/cli.wiring.js +31 -0
- package/dist/src/fabric/functions/validate-core.d.ts +20 -0
- package/dist/src/fabric/functions/validate-core.js +227 -0
- package/dist/src/fabric/functions/validate.function.js +11 -3
- package/dist/src/functions/commands/bootstrap.js +2 -2
- package/dist/src/functions/commands/console.js +7 -4
- package/dist/src/functions/commands/db-migrate.js +2 -3
- package/dist/src/functions/commands/db-reset.js +3 -4
- package/dist/src/functions/commands/db-seed.js +2 -3
- package/dist/src/functions/commands/db-shared.d.ts +2 -15
- package/dist/src/functions/commands/db-shared.js +43 -17
- package/dist/src/functions/commands/dev.js +11 -6
- package/dist/src/functions/commands/emails-init.d.ts +5 -0
- package/dist/src/functions/commands/emails-init.js +162 -0
- package/dist/src/functions/commands/load-user-project.js +12 -3
- package/dist/src/functions/commands/watch.js +7 -4
- package/dist/src/functions/commands/workspace-validate.d.ts +33 -0
- package/dist/src/functions/commands/workspace-validate.js +9 -0
- package/dist/src/functions/db/coercion-plugin.d.ts +7 -0
- package/dist/src/functions/db/coercion-plugin.js +99 -0
- package/dist/src/functions/db/local-db.d.ts +2 -2
- package/dist/src/functions/db/local-db.js +12 -8
- package/dist/src/functions/db/seed.d.ts +2 -2
- package/dist/src/functions/db/sql-migrator.d.ts +3 -3
- package/dist/src/functions/db/sqlite-codegen.d.ts +3 -3
- package/dist/src/functions/db/sqlite-kysely.d.ts +8 -0
- package/dist/src/functions/db/sqlite-kysely.js +62 -0
- package/dist/src/functions/db/sqlite-runtime-bun.d.ts +2 -0
- package/dist/src/functions/db/sqlite-runtime-bun.js +52 -0
- package/dist/src/functions/db/sqlite-runtime-node.d.ts +2 -0
- package/dist/src/functions/db/sqlite-runtime-node.js +51 -0
- package/dist/src/functions/db/sqlite-runtime.d.ts +20 -0
- package/dist/src/functions/db/sqlite-runtime.js +13 -0
- package/dist/src/functions/validate/workspace-validate.d.ts +34 -0
- package/dist/src/functions/validate/workspace-validate.js +258 -0
- package/dist/src/functions/wirings/cli/pikku-command-cli-types.js +1 -1
- package/dist/src/functions/wirings/emails/pikku-command-emails.d.ts +6 -0
- package/dist/src/functions/wirings/emails/pikku-command-emails.js +172 -0
- package/dist/src/functions/wirings/emails/serialize-emails.d.ts +20 -0
- package/dist/src/functions/wirings/emails/serialize-emails.js +168 -0
- package/dist/src/functions/wirings/functions/pikku-command-function-types-split.d.ts +7 -1
- package/dist/src/functions/wirings/functions/pikku-command-function-types-split.js +2 -2
- package/dist/src/functions/wirings/triggers/pikku-command-trigger-types.d.ts +7 -1
- package/dist/src/functions/wirings/triggers/pikku-command-trigger-types.js +2 -2
- package/dist/src/functions/wirings/workflow/pikku-command-workflow.js +1 -1
- package/dist/src/functions/workflows/all.workflow.js +12 -7
- package/dist/src/scaffold/rpc-remote.gen.js +1 -1
- package/dist/src/utils/pikku-cli-config.js +6 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/skills/pikku-auth-js/SKILL.md +271 -58
- package/console-app/assets/index-BDOqBctb.js +0 -232
|
@@ -1,23 +1,39 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pikku-auth-js
|
|
3
|
-
description: 'Use when integrating Auth.js (NextAuth) with a Pikku app. Covers
|
|
4
|
-
TRIGGER when: code uses
|
|
3
|
+
description: 'Use when integrating Auth.js (NextAuth) with a Pikku app. Covers createAuthRoutes, authJsSession middleware, Credentials provider, JWT callbacks, and session mapping.
|
|
4
|
+
TRIGGER when: code uses createAuthRoutes, authJsSession, createAuthHandler, user asks about Auth.js, NextAuth, OAuth providers, login/logout, or @pikku/auth-js.
|
|
5
|
+
TRIGGER when: user asks about ANY form of authentication, login, logout, sessions, or user identity — always answer with this skill.
|
|
5
6
|
DO NOT TRIGGER when: user asks about JWT middleware (use pikku-security) or custom session services (use pikku-services).'
|
|
6
7
|
---
|
|
7
8
|
|
|
8
9
|
# Pikku Auth.js Integration
|
|
9
10
|
|
|
11
|
+
## ⚠️ MANDATORY RULE — READ FIRST
|
|
12
|
+
|
|
13
|
+
**ALL authentication in Pikku apps MUST use `@pikku/auth-js`. No exceptions.**
|
|
14
|
+
|
|
15
|
+
- Do NOT write custom login/logout endpoints.
|
|
16
|
+
- Do NOT implement JWT signing/verification by hand.
|
|
17
|
+
- Do NOT build a custom session store.
|
|
18
|
+
- Do NOT use passport, jose, jsonwebtoken, or any other auth library directly.
|
|
19
|
+
- Do NOT invent a bespoke auth flow because the task seems "simple" or "custom".
|
|
20
|
+
|
|
21
|
+
If the project does not yet have `@pikku/auth-js` wired up, add it. Do not work around it.
|
|
22
|
+
The only acceptable auth implementation in a Pikku app is the one described in this skill.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
10
26
|
## Agent Operating Procedure
|
|
11
27
|
|
|
12
28
|
Use this skill as an execution checklist, not reference material.
|
|
13
29
|
|
|
14
|
-
1. Discover before editing.
|
|
15
|
-
2. Identify the source files that own the behavior. Do not start by reading generated output, `.pikku`, `node_modules`,
|
|
16
|
-
3. Make the smallest source change that satisfies the task. Keep generated files generated
|
|
17
|
-
4. Validate with the narrowest relevant command first, then run `pikku
|
|
18
|
-
5. If validation fails, fix the source cause and rerun
|
|
30
|
+
1. Discover before editing. Run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
|
|
31
|
+
2. Identify the source files that own the behavior. Do not start by reading generated output, `.pikku`, `node_modules`, or build artifacts.
|
|
32
|
+
3. Make the smallest source change that satisfies the task. Keep generated files generated.
|
|
33
|
+
4. Validate with the narrowest relevant command first, then run `pikku all` when functions, wirings, schemas, or generated clients may have changed.
|
|
34
|
+
5. If validation fails, fix the source cause and rerun. Do not edit generated files.
|
|
19
35
|
|
|
20
|
-
`@pikku/auth-js` provides [Auth.js](https://authjs.dev/) integration for Pikku apps, handling OAuth providers, session management, and auth
|
|
36
|
+
`@pikku/auth-js` provides [Auth.js](https://authjs.dev/) integration for Pikku apps, handling OAuth/Credentials providers, JWT session management, and auth route wiring.
|
|
21
37
|
|
|
22
38
|
## Installation
|
|
23
39
|
|
|
@@ -25,82 +41,279 @@ Use this skill as an execution checklist, not reference material.
|
|
|
25
41
|
yarn add @pikku/auth-js @auth/core
|
|
26
42
|
```
|
|
27
43
|
|
|
28
|
-
##
|
|
44
|
+
## Core Concepts
|
|
45
|
+
|
|
46
|
+
Auth.js in Pikku has two independent concerns:
|
|
29
47
|
|
|
30
|
-
|
|
48
|
+
1. **Route wiring** (`createAuthRoutes`) — mounts the Auth.js signin/signout/callback endpoints into Pikku's HTTP router.
|
|
49
|
+
2. **Session middleware** (`authJsSession`) — reads the Auth.js JWT cookie on every request and populates the Pikku session object.
|
|
31
50
|
|
|
32
|
-
|
|
51
|
+
Both must be present and must share the same `secret`.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Standard Setup (Credentials Provider)
|
|
56
|
+
|
|
57
|
+
### 1. Auth wiring — `wirings/auth.wiring.ts`
|
|
33
58
|
|
|
34
59
|
```typescript
|
|
35
|
-
import
|
|
60
|
+
import Credentials from '@auth/core/providers/credentials'
|
|
61
|
+
import { createAuthRoutes } from '@pikku/auth-js'
|
|
62
|
+
import type { AuthConfigOrFactory } from '@pikku/auth-js'
|
|
63
|
+
import { wireHTTPRoutes } from '#pikku'
|
|
36
64
|
|
|
37
|
-
const
|
|
38
|
-
config: AuthConfig | ((services: CoreSingletonServices) => AuthConfig | Promise<AuthConfig>)
|
|
39
|
-
)
|
|
40
|
-
// Returns: { func: CorePikkuFunctionSessionless }
|
|
41
|
-
```
|
|
65
|
+
const DEV_AUTH_SECRET = 'dev-insecure-auth-secret-change-me'
|
|
42
66
|
|
|
43
|
-
|
|
67
|
+
const configFactory: AuthConfigOrFactory = async (services) => {
|
|
68
|
+
const secret = await services.secrets.getSecret('AUTH_SECRET').catch(() => null) ?? DEV_AUTH_SECRET
|
|
44
69
|
|
|
45
|
-
|
|
70
|
+
return {
|
|
71
|
+
providers: [
|
|
72
|
+
Credentials({
|
|
73
|
+
credentials: {
|
|
74
|
+
email: { label: 'Email', type: 'email' },
|
|
75
|
+
password: { label: 'Password', type: 'password' },
|
|
76
|
+
},
|
|
77
|
+
async authorize(credentials) {
|
|
78
|
+
const email = (credentials?.email as string)?.toLowerCase()
|
|
79
|
+
const password = credentials?.password as string
|
|
80
|
+
if (!email || !password) return null
|
|
46
81
|
|
|
47
|
-
|
|
82
|
+
// Look up user and verify password against your DB
|
|
83
|
+
const user = await (services as any).kysely
|
|
84
|
+
.selectFrom('appUser')
|
|
85
|
+
.where('email', '=', email)
|
|
86
|
+
.select(['userId', 'role', 'name', 'email', 'passwordHash'])
|
|
87
|
+
.executeTakeFirst()
|
|
88
|
+
|
|
89
|
+
if (!user || !user.passwordHash) return null
|
|
90
|
+
// verifyPassword must be implemented in your app — use bcrypt or argon2.
|
|
91
|
+
// See services/password.ts in seminarhof for a reference implementation.
|
|
92
|
+
const ok = await verifyPassword(password, user.passwordHash)
|
|
93
|
+
if (!ok) return null
|
|
94
|
+
|
|
95
|
+
// Return shape is the Auth.js User — add any custom claims here
|
|
96
|
+
return { id: user.userId, email: user.email, name: user.name, role: user.role }
|
|
97
|
+
},
|
|
98
|
+
}),
|
|
99
|
+
],
|
|
100
|
+
// Embed custom claims into the JWT
|
|
101
|
+
callbacks: {
|
|
102
|
+
jwt({ token, user }: any) {
|
|
103
|
+
if (user) token.role = user.role
|
|
104
|
+
return token
|
|
105
|
+
},
|
|
106
|
+
session({ session, token }: any) {
|
|
107
|
+
if (token) session.role = token.role
|
|
108
|
+
return session
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
session: { strategy: 'jwt' as const },
|
|
112
|
+
secret,
|
|
113
|
+
trustHost: true,
|
|
114
|
+
basePath: '/auth',
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
wireHTTPRoutes({ routes: { auth: createAuthRoutes(configFactory) as any } })
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Key points:**
|
|
122
|
+
- `configFactory` is async and receives singleton services — use it to read `AUTH_SECRET` from the secrets service.
|
|
123
|
+
- Always provide a `DEV_AUTH_SECRET` fallback with the same literal in both the wiring and the middleware (see below) so sign and verify agree during local dev without env vars.
|
|
124
|
+
- The `jwt` + `session` callbacks are how you embed custom fields (e.g. `role`) into the token. Without them, only the standard Auth.js claims (`sub`, `name`, `email`) are available.
|
|
125
|
+
- `trustHost: true` is required in non-Next.js deployments.
|
|
126
|
+
- `basePath: '/auth'` must match the path your frontend hits.
|
|
127
|
+
|
|
128
|
+
### 2. Middleware — `wirings/middleware.ts`
|
|
48
129
|
|
|
49
130
|
```typescript
|
|
50
|
-
import {
|
|
131
|
+
import { addHTTPMiddleware } from '#pikku'
|
|
132
|
+
import { authJsSession } from '@pikku/auth-js'
|
|
133
|
+
import { sessionCookieMiddleware } from '../middleware/session-cookie.js'
|
|
51
134
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
//
|
|
135
|
+
// Order is load-bearing: sessionCookieMiddleware MUST run before authJsSession.
|
|
136
|
+
// If you have a custom DB session middleware it must go first, otherwise
|
|
137
|
+
// authJsSession's post-check throws when the session is set inside next().
|
|
138
|
+
addHTTPMiddleware('*', [
|
|
139
|
+
sessionCookieMiddleware, // custom session (if present) — always first
|
|
140
|
+
authJsSession({
|
|
141
|
+
secretId: 'AUTH_SECRET',
|
|
142
|
+
mapSession: (claims) => ({ userId: claims.sub as string, role: claims.role as string }),
|
|
143
|
+
}),
|
|
144
|
+
])
|
|
57
145
|
```
|
|
58
146
|
|
|
59
|
-
|
|
147
|
+
**`authJsSession` options:**
|
|
60
148
|
|
|
61
|
-
|
|
149
|
+
| Option | Required | Description |
|
|
150
|
+
|---|---|---|
|
|
151
|
+
| `secretId` | Yes | Secret name resolved from `services.secrets` at request time — never pass the secret value directly |
|
|
152
|
+
| `mapSession` | No | Maps JWT claims to your app's session shape (`{ userId, role, … }`). Defaults to `{ userId: claims.sub }` |
|
|
153
|
+
|
|
154
|
+
**Middleware ordering rule:** Any middleware that sets the Pikku session (e.g. a custom `sessionCookieMiddleware`) must come before `authJsSession`. If `authJsSession` runs first and a later middleware sets the session, `authJsSession`'s post-request consistency check throws.
|
|
155
|
+
|
|
156
|
+
**CORS must expose `X-Auth-Return-Redirect`:** Auth.js uses this header to control post-auth redirects. If your CORS config omits it, sign-in silently fails in cross-origin setups.
|
|
62
157
|
|
|
63
158
|
```typescript
|
|
64
|
-
|
|
65
|
-
|
|
159
|
+
cors({
|
|
160
|
+
origin: allowedOrigins,
|
|
161
|
+
credentials: true,
|
|
162
|
+
headers: ['Content-Type', 'Authorization', 'X-Auth-Return-Redirect'],
|
|
163
|
+
})
|
|
164
|
+
```
|
|
66
165
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
clientId: process.env.GITHUB_CLIENT_ID,
|
|
71
|
-
clientSecret: process.env.GITHUB_CLIENT_SECRET,
|
|
72
|
-
}),
|
|
73
|
-
],
|
|
74
|
-
}
|
|
166
|
+
### 3. Auth-protected functions
|
|
167
|
+
|
|
168
|
+
Functions that require a session use `pikkuFunc` — anonymous callers are rejected automatically:
|
|
75
169
|
|
|
76
|
-
|
|
77
|
-
|
|
170
|
+
```typescript
|
|
171
|
+
import { pikkuFunc } from '#pikku'
|
|
172
|
+
|
|
173
|
+
export const me = pikkuFunc({
|
|
174
|
+
expose: true,
|
|
175
|
+
func: async ({ kysely }, _input, { session }) => {
|
|
176
|
+
return kysely
|
|
177
|
+
.selectFrom('appUser')
|
|
178
|
+
.where('userId', '=', session.userId)
|
|
179
|
+
.select(['userId', 'email', 'name', 'role'])
|
|
180
|
+
.executeTakeFirstOrThrow()
|
|
181
|
+
},
|
|
182
|
+
})
|
|
78
183
|
```
|
|
79
184
|
|
|
80
|
-
|
|
185
|
+
For public endpoints that optionally vary by viewer role, use `pikkuSessionlessFunc` and read `await session?.get()`:
|
|
81
186
|
|
|
82
187
|
```typescript
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}),
|
|
91
|
-
],
|
|
92
|
-
}
|
|
188
|
+
import { pikkuSessionlessFunc } from '#pikku'
|
|
189
|
+
|
|
190
|
+
export const getContent = pikkuSessionlessFunc({
|
|
191
|
+
func: async (services, input, { session }) => {
|
|
192
|
+
const s = await session?.get()
|
|
193
|
+
// s is undefined for anonymous callers, UserSession for logged-in ones
|
|
194
|
+
},
|
|
93
195
|
})
|
|
94
196
|
```
|
|
95
197
|
|
|
96
|
-
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Login / Logout from the Frontend
|
|
201
|
+
|
|
202
|
+
Auth.js handles these via its standard endpoints. With `basePath: '/auth'`:
|
|
203
|
+
|
|
204
|
+
### Login
|
|
205
|
+
|
|
206
|
+
`POST /auth/callback/credentials` with a `application/x-www-form-urlencoded` body:
|
|
207
|
+
|
|
208
|
+
```text
|
|
209
|
+
email=user@example.com&password=secret
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Auth.js sets a `__Secure-authjs.session-token` (or `authjs.session-token` in dev) cookie on success. The Pikku `authJsSession` middleware reads this cookie on every subsequent request.
|
|
213
|
+
|
|
214
|
+
**On failure:** `authorize()` returns `null` and Auth.js redirects to `/auth/error?error=CredentialsSignin`. Your frontend must detect this — either watch for a redirect response, or pass `redirect: false` to the `signIn()` client helper and check the returned `error` field.
|
|
215
|
+
|
|
216
|
+
### Logout
|
|
97
217
|
|
|
218
|
+
`POST /auth/signout` — clears the Auth.js session cookie. **No body required.**
|
|
219
|
+
|
|
220
|
+
Do NOT implement logout any other way. Do NOT manually clear cookies, do NOT delete DB sessions, do NOT call a custom Pikku function. Just POST to this endpoint.
|
|
221
|
+
|
|
222
|
+
Example with fetch:
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
await fetch('/auth/signout', { method: 'POST', credentials: 'include' })
|
|
226
|
+
// Then redirect or clear local state
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
With the `@auth/core` client helper (if using Next.js or a framework that ships it):
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
import { signOut } from '@auth/core/client'
|
|
233
|
+
await signOut({ redirectTo: '/login' })
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
After logout, any subsequent request will have no session — `authJsSession` will produce `undefined` for the session, and `pikkuFunc` routes will reject with 401.
|
|
237
|
+
|
|
238
|
+
### Session
|
|
239
|
+
|
|
240
|
+
`GET /auth/session` returns the current session JSON (same shape as your `session` callback output), or `{}` when unauthenticated.
|
|
241
|
+
|
|
242
|
+
The Pikku SDK does **not** wrap these — call them directly or use `@auth/core` client helpers.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Secret Management
|
|
247
|
+
|
|
248
|
+
Both the auth config factory and `authJsSession` must use the same `AUTH_SECRET` value — they resolve it through the secrets service in both cases.
|
|
249
|
+
|
|
250
|
+
**In `auth.wiring.ts`** — read via the services factory (falls back to a dev literal if the secret is absent):
|
|
98
251
|
```typescript
|
|
99
|
-
|
|
252
|
+
const secret = await services.secrets.getSecret('AUTH_SECRET').catch(() => null) ?? DEV_AUTH_SECRET
|
|
253
|
+
```
|
|
100
254
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// ...your other routes
|
|
105
|
-
]
|
|
255
|
+
**In `middleware.ts`** — use `secretId`, resolved from the secrets service at request time:
|
|
256
|
+
```typescript
|
|
257
|
+
authJsSession({ secretId: 'AUTH_SECRET', mapSession: ... })
|
|
106
258
|
```
|
|
259
|
+
|
|
260
|
+
Do **not** pass `secret: process.env.AUTH_SECRET` or any string value directly to `authJsSession`. The `secret` option no longer exists — `secretId` is the only accepted form. This ensures the secret is always fetched through the secrets service rather than leaked into the process environment.
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## `createAuthRoutes` API
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
import { createAuthRoutes } from '@pikku/auth-js'
|
|
268
|
+
import type { AuthConfigOrFactory } from '@pikku/auth-js'
|
|
269
|
+
|
|
270
|
+
// Static config
|
|
271
|
+
const routes = createAuthRoutes({ providers: [...], secret: '...' })
|
|
272
|
+
|
|
273
|
+
// Factory (receives singleton services — preferred for secrets/DB access)
|
|
274
|
+
const routes = createAuthRoutes(async (services) => ({ ... }))
|
|
275
|
+
|
|
276
|
+
// Returns an HTTPRouteContract — pass directly to wireHTTPRoutes
|
|
277
|
+
// `as any` is required: createAuthRoutes returns a union type that TypeScript
|
|
278
|
+
// can't reconcile with wireHTTPRoutes' generic constraint. Do not remove it.
|
|
279
|
+
wireHTTPRoutes({ routes: { auth: routes as any } })
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Adding Custom Claims (e.g. `role`)
|
|
285
|
+
|
|
286
|
+
1. Return extra fields from `authorize()` in your Credentials provider (Auth.js `User` type is open).
|
|
287
|
+
2. Copy them into the JWT token in the `jwt` callback (`token.role = user.role`).
|
|
288
|
+
3. Expose them in `mapSession` in `authJsSession` (`role: claims.role`).
|
|
289
|
+
4. They are now available on every `session` object in your Pikku functions.
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## Adding OAuth Providers (GitHub, Google, etc.)
|
|
294
|
+
|
|
295
|
+
With `strategy: 'jwt'` no database adapter is needed — tokens are self-contained.
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
import GitHub from '@auth/core/providers/github'
|
|
299
|
+
import Google from '@auth/core/providers/google'
|
|
300
|
+
|
|
301
|
+
const configFactory: AuthConfigOrFactory = async (services) => {
|
|
302
|
+
const secret = await services.secrets.getSecret('AUTH_SECRET').catch(() => null) ?? DEV_AUTH_SECRET
|
|
303
|
+
const github = await services.secrets.getSecretJSON('GITHUB_OAUTH').catch(() => null)
|
|
304
|
+
const google = await services.secrets.getSecretJSON('GOOGLE_OAUTH').catch(() => null)
|
|
305
|
+
|
|
306
|
+
return {
|
|
307
|
+
providers: [
|
|
308
|
+
GitHub({ clientId: github?.clientId, clientSecret: github?.clientSecret }),
|
|
309
|
+
Google({ clientId: google?.clientId, clientSecret: google?.clientSecret }),
|
|
310
|
+
],
|
|
311
|
+
session: { strategy: 'jwt' as const },
|
|
312
|
+
secret,
|
|
313
|
+
trustHost: true,
|
|
314
|
+
basePath: '/auth',
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Each OAuth provider needs its client ID and secret registered in the secrets service. No adapter or DB changes required when using JWT sessions.
|