@absolutejs/auth 0.80.0 → 0.81.0
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/CHANGELOG.md +20 -0
- package/README.md +2 -0
- package/changelog.json +37 -0
- package/dist/credentials/api.d.ts +214 -0
- package/dist/credentials/emailVerification.d.ts +189 -1
- package/dist/credentials/integration.d.ts +3 -0
- package/dist/credentials/login.d.ts +208 -1
- package/dist/credentials/passwordReset.d.ts +197 -1
- package/dist/credentials/register.d.ts +198 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +64 -32
- package/dist/index.js.map +10 -9
- package/dist/manifest.js +53 -2
- package/dist/manifest.js.map +5 -4
- package/dist/manifest.json +25 -1
- package/dist/server.d.ts +1 -0
- package/dist/server.js +64 -32
- package/dist/server.js.map +10 -9
- package/docs/PERSISTENT-CREDENTIALS.md +131 -0
- package/package.json +4 -3
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Persistent email/password sign-in (Bun + Elysia 2)
|
|
2
|
+
|
|
3
|
+
Use this credentials-only setup instead of the social-login manifest recipe.
|
|
4
|
+
The same API pattern passed synthetic browser signup, login, logout, booking and
|
|
5
|
+
full-container restart tests in Studio using auth 0.80.0. The example deliberately
|
|
6
|
+
sends no email and refuses production. For a real business configure email
|
|
7
|
+
verification, delivery, password policy, backups and the application's user schema.
|
|
8
|
+
|
|
9
|
+
Install published auth and a compatible Drizzle release. Set AUTH_DATABASE_URL
|
|
10
|
+
securely to a real isolated PostgreSQL database; never substitute a placeholder.
|
|
11
|
+
The application owns user records. The auth package owns credentials and sessions.
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { auth } from '@absolutejs/auth/server';
|
|
15
|
+
import { createPostgresAuthSessionStore, createPostgresCredentialStore, runMigrations } from '@absolutejs/auth';
|
|
16
|
+
import { SQL } from 'bun';
|
|
17
|
+
import { Database } from 'bun:sqlite';
|
|
18
|
+
import { drizzle } from 'drizzle-orm/bun-sql';
|
|
19
|
+
import { mkdirSync } from 'node:fs';
|
|
20
|
+
|
|
21
|
+
if (process.env.NODE_ENV === 'production') throw new Error('Synthetic example: configure verified email and real business policy before production');
|
|
22
|
+
type Customer = { id: string; email: string };
|
|
23
|
+
const databaseUrl = process.env.AUTH_DATABASE_URL;
|
|
24
|
+
if (!databaseUrl)
|
|
25
|
+
throw new Error(
|
|
26
|
+
"AUTH_DATABASE_URL must point to the isolated acceptance database",
|
|
27
|
+
);
|
|
28
|
+
const migrationClient = new SQL({ url: databaseUrl, max: 1, prepare: false });
|
|
29
|
+
try {
|
|
30
|
+
await runMigrations({
|
|
31
|
+
blocks: ["sessions", "credentials"],
|
|
32
|
+
client: {
|
|
33
|
+
query: async (text, values) => ({
|
|
34
|
+
rows: await migrationClient.unsafe(text, values ? [...values] : []),
|
|
35
|
+
}),
|
|
36
|
+
},
|
|
37
|
+
log: () => undefined,
|
|
38
|
+
});
|
|
39
|
+
} finally {
|
|
40
|
+
await migrationClient.close();
|
|
41
|
+
}
|
|
42
|
+
const authDb = drizzle({ client: new SQL(databaseUrl) });
|
|
43
|
+
const decodeCustomer = (value: unknown): Customer => {
|
|
44
|
+
if (typeof value !== "object" || value === null)
|
|
45
|
+
throw new Error("Invalid customer session");
|
|
46
|
+
const id: unknown = Reflect.get(value, "id");
|
|
47
|
+
const email: unknown = Reflect.get(value, "email");
|
|
48
|
+
if (typeof id !== "string" || typeof email !== "string")
|
|
49
|
+
throw new Error("Invalid customer session");
|
|
50
|
+
return { id, email };
|
|
51
|
+
};
|
|
52
|
+
mkdirSync(".data", { recursive: true });
|
|
53
|
+
const db = new Database(".data/customer-example.sqlite", { create: true });
|
|
54
|
+
db.exec(
|
|
55
|
+
"PRAGMA journal_mode=WAL; PRAGMA busy_timeout=5000; CREATE TABLE IF NOT EXISTS customers(id TEXT PRIMARY KEY, email TEXT NOT NULL UNIQUE);",
|
|
56
|
+
);
|
|
57
|
+
const userById = db.query<Customer, [string]>(
|
|
58
|
+
"SELECT id,email FROM customers WHERE id=?",
|
|
59
|
+
);
|
|
60
|
+
const userByEmail = db.query<Customer, [string]>(
|
|
61
|
+
"SELECT id,email FROM customers WHERE email=?",
|
|
62
|
+
);
|
|
63
|
+
const insertUser = db.query("INSERT INTO customers(id,email) VALUES(?,?)");
|
|
64
|
+
const sessions = createPostgresAuthSessionStore(authDb, decodeCustomer);
|
|
65
|
+
export const authentication = await auth<Customer>({
|
|
66
|
+
providersConfiguration: {},
|
|
67
|
+
getUser: (id) => userById.get(String(id)) ?? null,
|
|
68
|
+
authSessionStore: sessions,
|
|
69
|
+
cookieSecure: true,
|
|
70
|
+
credentials: {
|
|
71
|
+
credentialStore: createPostgresCredentialStore(authDb),
|
|
72
|
+
getUserByEmail: (email) => userByEmail.get(email) ?? null,
|
|
73
|
+
onCreateCredentialUser: ({ email }) => {
|
|
74
|
+
const user = { id: crypto.randomUUID(), email };
|
|
75
|
+
insertUser.run(user.id, email);
|
|
76
|
+
return user;
|
|
77
|
+
},
|
|
78
|
+
// Local synthetic mode deliberately delivers no messages.
|
|
79
|
+
onSendEmail: () => undefined,
|
|
80
|
+
requireEmailVerification: false,
|
|
81
|
+
passwordPolicy: { minLength: 12, checkBreaches: false },
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Important API details:
|
|
88
|
+
|
|
89
|
+
- `auth` is asynchronous and comes from `@absolutejs/auth/server`.
|
|
90
|
+
- `authSessionStore` is top-level. `credentialStore` and credential callbacks
|
|
91
|
+
belong inside `credentials`. There is no top-level `sessionStore` option.
|
|
92
|
+
- Stores do not have `.runMigrations()`. Import `runMigrations` from the package
|
|
93
|
+
root and supply its query client as shown above.
|
|
94
|
+
- With Drizzle 1's Bun driver use `drizzle({ client })`, not `drizzle(client)`.
|
|
95
|
+
- Keep `prepare: false` on the migration client only. Application queries need
|
|
96
|
+
Bun's default prepared mode to encode JSON session data correctly.
|
|
97
|
+
- The built-in sign-out route is `DELETE /oauth2/signout`.
|
|
98
|
+
- Use `createAuthContext<Customer>({ authSessionStore: sessions })` from `/server` to read typed authenticated
|
|
99
|
+
users. Business APIs must check the session server-side and scope records to
|
|
100
|
+
that user. Do not implement a second password or cookie system.
|
|
101
|
+
- Preserve cookie headers when exposing a narrow typed JSON wrapper around the
|
|
102
|
+
package's configurable credential routes. Never store session tokens in browser
|
|
103
|
+
localStorage. Browser business requests belong in typed Eden + React Query.
|
|
104
|
+
|
|
105
|
+
## Typed credential routes (0.81.0+)
|
|
106
|
+
|
|
107
|
+
Use `createCredentialsApi` from `@absolutejs/auth/server` for fixed, directly
|
|
108
|
+
Eden-typed login, registration, verification and password-reset routes. Supply
|
|
109
|
+
application-owned credentials callbacks, cookie policy and a durable session
|
|
110
|
+
store. Mount this subapp instead of the `credentials` block on `auth`; keep
|
|
111
|
+
`auth` for OAuth/sign-out. No forwarding wrappers are needed.
|
|
112
|
+
|
|
113
|
+
The manifest tool `get_credentials_integration` returns the exact integration
|
|
114
|
+
source and required bindings. `credentialsConfiguration` is your application
|
|
115
|
+
module, not a package export: it supplies `authSessionStore`, `credentialStore`,
|
|
116
|
+
`getUserByEmail`, `onCreateCredentialUser`, and real `onSendEmail` delivery.
|
|
117
|
+
Configure trusted origins, verification and password policy. Never invent these
|
|
118
|
+
bindings, substitute in-memory production storage, or silently disable delivery.
|
|
119
|
+
|
|
120
|
+
Browser code imports only `typeof credentialsApi` and creates
|
|
121
|
+
`treaty<typeof credentialsApi>(origin)`. Call `client.auth.login.post(...)` in a
|
|
122
|
+
React Query `mutationFn`. Inspect errors and preserve `mfa_required` and
|
|
123
|
+
`verification_required` flows: a successful HTTP response does not always mean
|
|
124
|
+
an authenticated session.
|
|
125
|
+
|
|
126
|
+
For protected business routes use `createAuthContext({ authSessionStore })`,
|
|
127
|
+
read `absoluteAuthStatus.user`, return `status(401, { error: 'Sign in required' })`
|
|
128
|
+
when absent, and scope database access to that user. Export the narrow business
|
|
129
|
+
subapp type for its own Eden client inside React Query. A compiler pass is
|
|
130
|
+
necessary, but real signup, login, reset, authorization and persistence tests
|
|
131
|
+
are still required.
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "0.81.0",
|
|
3
3
|
"name": "@absolutejs/auth",
|
|
4
4
|
"description": "An authorization library for absolutejs",
|
|
5
5
|
"repository": {
|
|
@@ -24,9 +24,10 @@
|
|
|
24
24
|
"lint": "absolute eslint",
|
|
25
25
|
"typecheck": "absolute typecheck",
|
|
26
26
|
"verify-package": "absolute-manifest verify-package",
|
|
27
|
-
"check:package": "bun run typecheck && bun run lint && bun run test && bun run build && bun run verify-package && absolute-changelog check",
|
|
27
|
+
"check:package": "bun run typecheck && bun run typecheck:credentials && bun run lint && bun run test && bun run build && bun run verify-package && absolute-changelog check",
|
|
28
28
|
"release": "bun run format && bun run check:package && npm publish",
|
|
29
|
-
"prepublishOnly": "bun run check:package"
|
|
29
|
+
"prepublishOnly": "bun run check:package",
|
|
30
|
+
"typecheck:credentials": "tsc --project tsconfig.credentials.json"
|
|
30
31
|
},
|
|
31
32
|
"keywords": [
|
|
32
33
|
"authorization",
|