@protobase/server 0.5.0 → 0.7.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/dist/better-auth/auth-schema.d.ts +16 -0
- package/dist/better-auth/auth-schema.js +45 -0
- package/dist/better-auth/create-auth.d.ts +189 -19
- package/dist/better-auth/create-auth.js +38 -9
- package/dist/better-auth/platform-sign-in.d.ts +30 -0
- package/dist/better-auth/platform-sign-in.js +88 -0
- package/dist/better-auth/policy-plugin.js +10 -5
- package/dist/better-auth/policy-store.js +44 -30
- package/dist/better-auth/sign-in-enforcement.js +11 -3
- package/dist/better-auth/sign-in-policy.d.ts +8 -1
- package/dist/better-auth/sign-in-policy.js +21 -7
- package/dist/better-auth/snake-case-migration.js +122 -0
- package/dist/better-auth/snake-case-names.js +72 -0
- package/dist/better-auth/staff-log.js +56 -45
- package/dist/better-auth/staff-plugin.js +1 -1
- package/dist/better-auth/status-route.js +10 -4
- package/dist/better-auth/users.d.ts +8 -1
- package/dist/better-auth/users.js +16 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +3 -1
- package/package.json +4 -4
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { AdminAuth } from "./create-auth.js";
|
|
2
|
+
//#region src/better-auth/auth-schema.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* The SQL that brings the admin store up to what this version of Protobase and the project's Better Auth plugins need:
|
|
5
|
+
* for a store with the camelCase names of Protobase 0.6, their rename to snake_case (`snakeCaseMigration`); otherwise
|
|
6
|
+
* new tables, columns and indexes, never a drop, each skipped where it exists. `undefined` when the store is current. A
|
|
7
|
+
* change Better Auth cannot make safely, such as a required column without a default on a table with rows, is an error.
|
|
8
|
+
*/
|
|
9
|
+
export declare const authSchemaMigration: (auth: AdminAuth) => Promise<string | undefined>;
|
|
10
|
+
/**
|
|
11
|
+
* Refuses to go on while the admin store lacks a table or column Better Auth needs, or still has the camelCase names
|
|
12
|
+
* of Protobase 0.6, since every sign-in would fail. The server never changes the schema itself: the project's
|
|
13
|
+
* migrations do, before the new version serves.
|
|
14
|
+
*/
|
|
15
|
+
export declare const checkAuthSchema: (auth: AdminAuth) => Promise<void>;
|
|
16
|
+
//#endregion
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { snakeCaseMigration } from "./snake-case-migration.js";
|
|
2
|
+
import { getMigrations } from "better-auth/db/migration";
|
|
3
|
+
//#region src/better-auth/auth-schema.ts
|
|
4
|
+
/** The command that writes the pending changes as a migration file of the project. */
|
|
5
|
+
const authMigrationCommand = "protobase auth migration";
|
|
6
|
+
/**
|
|
7
|
+
* Better Auth's statements, each made to skip what exists already, so a migration written from an empty database also
|
|
8
|
+
* applies to one an earlier Protobase set up in place.
|
|
9
|
+
*/
|
|
10
|
+
const skipExisting = (sql) => sql.split(";\n\n").map((statement) => statement.replace(/^create table (?!if not exists )/, "create table if not exists ").replace(/^create (unique )?index (?!if not exists )/, (_, unique) => `create ${unique ?? ""}index if not exists `).replace(/^(alter table .+? )add column (?!if not exists )/, "$1add column if not exists ")).join(";\n\n");
|
|
11
|
+
/**
|
|
12
|
+
* Better Auth adds `email_verified` to a `user` table that exists only when the table still has the camelCase names
|
|
13
|
+
* of Protobase 0.6, whose `emailVerified` it does not know: such a store is renamed, never given new columns beside
|
|
14
|
+
* the old ones.
|
|
15
|
+
*/
|
|
16
|
+
const hasCamelCaseNames = ({ toBeAdded }) => toBeAdded.some(({ table, fields }) => table === "user" && "email_verified" in fields);
|
|
17
|
+
const storeSchema = ({ options: { database } }) => database && "schemaName" in database ? database.schemaName : void 0;
|
|
18
|
+
/**
|
|
19
|
+
* The SQL that brings the admin store up to what this version of Protobase and the project's Better Auth plugins need:
|
|
20
|
+
* for a store with the camelCase names of Protobase 0.6, their rename to snake_case (`snakeCaseMigration`); otherwise
|
|
21
|
+
* new tables, columns and indexes, never a drop, each skipped where it exists. `undefined` when the store is current. A
|
|
22
|
+
* change Better Auth cannot make safely, such as a required column without a default on a table with rows, is an error.
|
|
23
|
+
*/
|
|
24
|
+
const authSchemaMigration = async (auth) => {
|
|
25
|
+
if (hasCamelCaseNames(await getMigrations(auth.options, { throwOnUnsafe: false }))) return snakeCaseMigration(storeSchema(auth));
|
|
26
|
+
const { toBeCreated, toBeAdded, toBeAddedIndexes, compileMigrations } = await getMigrations(auth.options);
|
|
27
|
+
if (toBeCreated.length === 0 && toBeAdded.length === 0 && toBeAddedIndexes.length === 0) return void 0;
|
|
28
|
+
return skipExisting(await compileMigrations());
|
|
29
|
+
};
|
|
30
|
+
/** The tables and `table.column`s the admin store lacks; an index missing is not a reason to refuse requests. */
|
|
31
|
+
const missingTablesAndColumns = ({ toBeCreated, toBeAdded }) => [...toBeCreated.map(({ table }) => table), ...toBeAdded.flatMap(({ table, fields }) => Object.keys(fields).map((field) => `${table}.${field}`))];
|
|
32
|
+
/**
|
|
33
|
+
* Refuses to go on while the admin store lacks a table or column Better Auth needs, or still has the camelCase names
|
|
34
|
+
* of Protobase 0.6, since every sign-in would fail. The server never changes the schema itself: the project's
|
|
35
|
+
* migrations do, before the new version serves.
|
|
36
|
+
*/
|
|
37
|
+
const checkAuthSchema = async (auth) => {
|
|
38
|
+
const plan = await getMigrations(auth.options, { throwOnUnsafe: false });
|
|
39
|
+
if (hasCamelCaseNames(plan)) throw new Error(`The auth schema still has the camelCase names of Protobase 0.6, which this version names in snake_case. Write their rename as a migration with \`${authMigrationCommand}\`, apply it with the project's migrations, then start again.`);
|
|
40
|
+
const missing = missingTablesAndColumns(plan);
|
|
41
|
+
if (missing.length === 0) return;
|
|
42
|
+
throw new Error(`The auth schema is behind this version of Protobase (missing ${missing.join(", ")}). Write the change as a migration with \`${authMigrationCommand}\`, apply it with the project's migrations, then start again.`);
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
export { authMigrationCommand, authSchemaMigration, checkAuthSchema, skipExisting };
|
|
@@ -2,6 +2,7 @@ import { SignInPolicy } from "./sign-in-policy.js";
|
|
|
2
2
|
import { StaffSignIn } from "./staff-log.js";
|
|
3
3
|
import { Mailer } from "../mail/smtp-mailer.js";
|
|
4
4
|
import { OperatorProvider } from "./operator-provider.js";
|
|
5
|
+
import { PlatformSignIn } from "./platform-sign-in.js";
|
|
5
6
|
import { BetterAuthOptions } from "better-auth";
|
|
6
7
|
//#region src/better-auth/create-auth.d.ts
|
|
7
8
|
export type CreateAuthOptions = {
|
|
@@ -33,7 +34,7 @@ export type CreateAuthOptions = {
|
|
|
33
34
|
/**
|
|
34
35
|
* Sign-in providers for Better Auth, for example `{ github: { clientId, clientSecret } }`; the callback is
|
|
35
36
|
* `{baseURL}/api/auth/callback/<provider>`. A provider also signs up people without an account, with the default role.
|
|
36
|
-
* Default none.
|
|
37
|
+
* One with the id of `signInProvider` takes its place. Default none.
|
|
37
38
|
*/
|
|
38
39
|
socialProviders?: BetterAuthOptions['socialProviders'];
|
|
39
40
|
/** Encrypt the OAuth access, refresh and ID tokens Better Auth stores for social sign-ins, with `secret`. Default off. */
|
|
@@ -47,6 +48,13 @@ export type CreateAuthOptions = {
|
|
|
47
48
|
* whatever the environment says.
|
|
48
49
|
*/
|
|
49
50
|
operator?: OperatorProvider | false;
|
|
51
|
+
/**
|
|
52
|
+
* A sign-in provider the platform adds for people who already have an account: an OpenID Connect provider that never
|
|
53
|
+
* signs anyone up. Defaults to the one the platform passes in `PROTOBASE_SIGN_IN_ISSUER`, `PROTOBASE_SIGN_IN_CLIENT_ID`
|
|
54
|
+
* and `PROTOBASE_SIGN_IN_CLIENT_SECRET` (see `readPlatformSignIn`), when set; `false` turns it off whatever the
|
|
55
|
+
* environment says. Left out when `socialProviders` has a provider with the same id.
|
|
56
|
+
*/
|
|
57
|
+
signInProvider?: PlatformSignIn | false;
|
|
50
58
|
};
|
|
51
59
|
type UserCreateHooks = NonNullable<NonNullable<NonNullable<BetterAuthOptions['databaseHooks']>['user']>['create']>;
|
|
52
60
|
/** Better Auth's `databaseHooks.user.create.after`: the created user (with its `role`) and the request context, `null` outside a request. */
|
|
@@ -54,6 +62,48 @@ export type UserCreatedHook = NonNullable<UserCreateHooks['after']>;
|
|
|
54
62
|
/** The configured roles with `admin` first; `admin` is added when missing. */
|
|
55
63
|
export declare const normalizeRoles: (roles?: string[]) => string[];
|
|
56
64
|
export declare const createAuth: (options: CreateAuthOptions) => import("better-auth").Auth<{
|
|
65
|
+
user: {
|
|
66
|
+
fields: {
|
|
67
|
+
emailVerified: string;
|
|
68
|
+
createdAt: string;
|
|
69
|
+
updatedAt: string;
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
session: {
|
|
73
|
+
fields: {
|
|
74
|
+
expiresAt: string;
|
|
75
|
+
createdAt: string;
|
|
76
|
+
updatedAt: string;
|
|
77
|
+
ipAddress: string;
|
|
78
|
+
userAgent: string;
|
|
79
|
+
userId: string;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
verification: {
|
|
83
|
+
fields: {
|
|
84
|
+
expiresAt: string;
|
|
85
|
+
createdAt: string;
|
|
86
|
+
updatedAt: string;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
account: {
|
|
90
|
+
encryptOAuthTokens?: true | undefined;
|
|
91
|
+
accountLinking: {
|
|
92
|
+
allowDifferentEmails: true;
|
|
93
|
+
};
|
|
94
|
+
fields: {
|
|
95
|
+
accountId: string;
|
|
96
|
+
providerId: string;
|
|
97
|
+
userId: string;
|
|
98
|
+
accessToken: string;
|
|
99
|
+
refreshToken: string;
|
|
100
|
+
idToken: string;
|
|
101
|
+
accessTokenExpiresAt: string;
|
|
102
|
+
refreshTokenExpiresAt: string;
|
|
103
|
+
createdAt: string;
|
|
104
|
+
updatedAt: string;
|
|
105
|
+
};
|
|
106
|
+
};
|
|
57
107
|
plugins: [{
|
|
58
108
|
id: "admin";
|
|
59
109
|
version: string;
|
|
@@ -940,6 +990,19 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
940
990
|
};
|
|
941
991
|
};
|
|
942
992
|
options: NoInfer<{
|
|
993
|
+
schema: {
|
|
994
|
+
user: {
|
|
995
|
+
fields: {
|
|
996
|
+
banReason: string;
|
|
997
|
+
banExpires: string;
|
|
998
|
+
};
|
|
999
|
+
};
|
|
1000
|
+
session: {
|
|
1001
|
+
fields: {
|
|
1002
|
+
impersonatedBy: string;
|
|
1003
|
+
};
|
|
1004
|
+
};
|
|
1005
|
+
};
|
|
943
1006
|
defaultRole: string;
|
|
944
1007
|
roles: {
|
|
945
1008
|
[k: string]: import("better-auth/plugins").Role<import("better-auth/plugins").ExactRoleStatements<{
|
|
@@ -961,6 +1024,16 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
961
1024
|
id: "jwt";
|
|
962
1025
|
version: string;
|
|
963
1026
|
options: NoInfer<{
|
|
1027
|
+
schema: {
|
|
1028
|
+
jwks: {
|
|
1029
|
+
fields: {
|
|
1030
|
+
publicKey: string;
|
|
1031
|
+
privateKey: string;
|
|
1032
|
+
createdAt: string;
|
|
1033
|
+
expiresAt: string;
|
|
1034
|
+
};
|
|
1035
|
+
};
|
|
1036
|
+
};
|
|
964
1037
|
jwt: {
|
|
965
1038
|
expirationTime: string;
|
|
966
1039
|
issuer: string;
|
|
@@ -2458,7 +2531,7 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
2458
2531
|
RESOLVED_USER_INVALID: import("better-auth").RawError<"RESOLVED_USER_INVALID">;
|
|
2459
2532
|
};
|
|
2460
2533
|
options: import("@better-auth/passkey").PasskeyOptions | undefined;
|
|
2461
|
-
}, ...{
|
|
2534
|
+
}, ...({
|
|
2462
2535
|
id: "email-otp";
|
|
2463
2536
|
version: string;
|
|
2464
2537
|
init(ctx: import("better-auth").AuthContext): {
|
|
@@ -2990,10 +3063,24 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
2990
3063
|
INVALID_OTP: import("better-auth").RawError<"INVALID_OTP">;
|
|
2991
3064
|
TOO_MANY_ATTEMPTS: import("better-auth").RawError<"TOO_MANY_ATTEMPTS">;
|
|
2992
3065
|
};
|
|
2993
|
-
}
|
|
3066
|
+
} | {
|
|
3067
|
+
id: "generic-oauth";
|
|
3068
|
+
version: string;
|
|
3069
|
+
init: (ctx: import("better-auth").AuthContext) => Promise<{
|
|
3070
|
+
context: {
|
|
3071
|
+
socialProviders: import("better-auth").OAuthProvider<object, Partial<import("better-auth").ProviderOptions<object>>>[];
|
|
3072
|
+
};
|
|
3073
|
+
}>;
|
|
3074
|
+
options: import("better-auth/plugins").GenericOAuthOptions<string>;
|
|
3075
|
+
$ERROR_CODES: {
|
|
3076
|
+
INVALID_OAUTH_CONFIGURATION: import("better-auth").RawError<"INVALID_OAUTH_CONFIGURATION">;
|
|
3077
|
+
TOKEN_URL_NOT_FOUND: import("better-auth").RawError<"TOKEN_URL_NOT_FOUND">;
|
|
3078
|
+
};
|
|
3079
|
+
})[], {
|
|
2994
3080
|
id: "protobase-sign-in-policy";
|
|
2995
3081
|
schema: {
|
|
2996
3082
|
readonly signInPolicy: {
|
|
3083
|
+
readonly modelName: "sign_in_policy";
|
|
2997
3084
|
readonly fields: {
|
|
2998
3085
|
readonly password: {
|
|
2999
3086
|
readonly type: "string";
|
|
@@ -3002,6 +3089,7 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3002
3089
|
readonly emailCode: {
|
|
3003
3090
|
readonly type: "string";
|
|
3004
3091
|
readonly required: true;
|
|
3092
|
+
readonly fieldName: "email_code";
|
|
3005
3093
|
};
|
|
3006
3094
|
readonly passkey: {
|
|
3007
3095
|
readonly type: "string";
|
|
@@ -3010,19 +3098,29 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3010
3098
|
readonly twoFactor: {
|
|
3011
3099
|
readonly type: "string";
|
|
3012
3100
|
readonly required: true;
|
|
3101
|
+
readonly fieldName: "two_factor";
|
|
3013
3102
|
};
|
|
3014
3103
|
readonly staffAccess: {
|
|
3015
3104
|
readonly type: "string";
|
|
3016
3105
|
readonly required: true;
|
|
3017
3106
|
readonly defaultValue: "allowed";
|
|
3107
|
+
readonly fieldName: "staff_access";
|
|
3108
|
+
};
|
|
3109
|
+
readonly platformSignIn: {
|
|
3110
|
+
readonly type: "string";
|
|
3111
|
+
readonly required: true;
|
|
3112
|
+
readonly defaultValue: "allowed";
|
|
3113
|
+
readonly fieldName: "platform_sign_in";
|
|
3018
3114
|
};
|
|
3019
3115
|
readonly createdAt: {
|
|
3020
3116
|
readonly type: "date";
|
|
3021
3117
|
readonly required: true;
|
|
3118
|
+
readonly fieldName: "created_at";
|
|
3022
3119
|
};
|
|
3023
3120
|
readonly createdBy: {
|
|
3024
3121
|
readonly type: "string";
|
|
3025
3122
|
readonly required: false;
|
|
3123
|
+
readonly fieldName: "created_by";
|
|
3026
3124
|
};
|
|
3027
3125
|
};
|
|
3028
3126
|
};
|
|
@@ -3041,7 +3139,12 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3041
3139
|
expiresAt: Date;
|
|
3042
3140
|
token: string;
|
|
3043
3141
|
ipAddress?: string | null | undefined;
|
|
3044
|
-
userAgent
|
|
3142
|
+
userAgent? /**
|
|
3143
|
+
* A sign-in provider the platform adds for people who already have an account: an OpenID Connect provider that never
|
|
3144
|
+
* signs anyone up. Defaults to the one the platform passes in `PROTOBASE_SIGN_IN_ISSUER`, `PROTOBASE_SIGN_IN_CLIENT_ID`
|
|
3145
|
+
* and `PROTOBASE_SIGN_IN_CLIENT_SECRET` (see `readPlatformSignIn`), when set; `false` turns it off whatever the
|
|
3146
|
+
* environment says. Left out when `socialProviders` has a provider with the same id.
|
|
3147
|
+
*/ : string | null | undefined;
|
|
3045
3148
|
};
|
|
3046
3149
|
user: Record<string, any> & {
|
|
3047
3150
|
id: string;
|
|
@@ -3065,7 +3168,12 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3065
3168
|
expiresAt: Date;
|
|
3066
3169
|
token: string;
|
|
3067
3170
|
ipAddress?: string | null | undefined;
|
|
3068
|
-
userAgent
|
|
3171
|
+
userAgent? /**
|
|
3172
|
+
* A sign-in provider the platform adds for people who already have an account: an OpenID Connect provider that never
|
|
3173
|
+
* signs anyone up. Defaults to the one the platform passes in `PROTOBASE_SIGN_IN_ISSUER`, `PROTOBASE_SIGN_IN_CLIENT_ID`
|
|
3174
|
+
* and `PROTOBASE_SIGN_IN_CLIENT_SECRET` (see `readPlatformSignIn`), when set; `false` turns it off whatever the
|
|
3175
|
+
* environment says. Left out when `socialProviders` has a provider with the same id.
|
|
3176
|
+
*/ : string | null | undefined;
|
|
3069
3177
|
};
|
|
3070
3178
|
user: Record<string, any> & {
|
|
3071
3179
|
id: string;
|
|
@@ -3088,7 +3196,12 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3088
3196
|
expiresAt: Date;
|
|
3089
3197
|
token: string;
|
|
3090
3198
|
ipAddress?: string | null | undefined;
|
|
3091
|
-
userAgent
|
|
3199
|
+
userAgent? /**
|
|
3200
|
+
* A sign-in provider the platform adds for people who already have an account: an OpenID Connect provider that never
|
|
3201
|
+
* signs anyone up. Defaults to the one the platform passes in `PROTOBASE_SIGN_IN_ISSUER`, `PROTOBASE_SIGN_IN_CLIENT_ID`
|
|
3202
|
+
* and `PROTOBASE_SIGN_IN_CLIENT_SECRET` (see `readPlatformSignIn`), when set; `false` turns it off whatever the
|
|
3203
|
+
* environment says. Left out when `socialProviders` has a provider with the same id.
|
|
3204
|
+
*/ : string | null | undefined;
|
|
3092
3205
|
};
|
|
3093
3206
|
user: Record<string, any> & {
|
|
3094
3207
|
id: string;
|
|
@@ -3124,6 +3237,7 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3124
3237
|
}, {
|
|
3125
3238
|
savedBy?: string | undefined;
|
|
3126
3239
|
savedAt?: string | undefined;
|
|
3240
|
+
platformSignIn?: string | undefined;
|
|
3127
3241
|
operator?: string | undefined;
|
|
3128
3242
|
policy: SignInPolicy;
|
|
3129
3243
|
effective: SignInPolicy;
|
|
@@ -3142,7 +3256,12 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3142
3256
|
expiresAt: Date;
|
|
3143
3257
|
token: string;
|
|
3144
3258
|
ipAddress?: string | null | undefined;
|
|
3145
|
-
userAgent
|
|
3259
|
+
userAgent? /**
|
|
3260
|
+
* A sign-in provider the platform adds for people who already have an account: an OpenID Connect provider that never
|
|
3261
|
+
* signs anyone up. Defaults to the one the platform passes in `PROTOBASE_SIGN_IN_ISSUER`, `PROTOBASE_SIGN_IN_CLIENT_ID`
|
|
3262
|
+
* and `PROTOBASE_SIGN_IN_CLIENT_SECRET` (see `readPlatformSignIn`), when set; `false` turns it off whatever the
|
|
3263
|
+
* environment says. Left out when `socialProviders` has a provider with the same id.
|
|
3264
|
+
*/ : string | null | undefined;
|
|
3146
3265
|
};
|
|
3147
3266
|
user: Record<string, any> & {
|
|
3148
3267
|
id: string;
|
|
@@ -3166,7 +3285,12 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3166
3285
|
expiresAt: Date;
|
|
3167
3286
|
token: string;
|
|
3168
3287
|
ipAddress?: string | null | undefined;
|
|
3169
|
-
userAgent
|
|
3288
|
+
userAgent? /**
|
|
3289
|
+
* A sign-in provider the platform adds for people who already have an account: an OpenID Connect provider that never
|
|
3290
|
+
* signs anyone up. Defaults to the one the platform passes in `PROTOBASE_SIGN_IN_ISSUER`, `PROTOBASE_SIGN_IN_CLIENT_ID`
|
|
3291
|
+
* and `PROTOBASE_SIGN_IN_CLIENT_SECRET` (see `readPlatformSignIn`), when set; `false` turns it off whatever the
|
|
3292
|
+
* environment says. Left out when `socialProviders` has a provider with the same id.
|
|
3293
|
+
*/ : string | null | undefined;
|
|
3170
3294
|
};
|
|
3171
3295
|
user: Record<string, any> & {
|
|
3172
3296
|
id: string;
|
|
@@ -3189,7 +3313,12 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3189
3313
|
expiresAt: Date;
|
|
3190
3314
|
token: string;
|
|
3191
3315
|
ipAddress?: string | null | undefined;
|
|
3192
|
-
userAgent
|
|
3316
|
+
userAgent? /**
|
|
3317
|
+
* A sign-in provider the platform adds for people who already have an account: an OpenID Connect provider that never
|
|
3318
|
+
* signs anyone up. Defaults to the one the platform passes in `PROTOBASE_SIGN_IN_ISSUER`, `PROTOBASE_SIGN_IN_CLIENT_ID`
|
|
3319
|
+
* and `PROTOBASE_SIGN_IN_CLIENT_SECRET` (see `readPlatformSignIn`), when set; `false` turns it off whatever the
|
|
3320
|
+
* environment says. Left out when `socialProviders` has a provider with the same id.
|
|
3321
|
+
*/ : string | null | undefined;
|
|
3193
3322
|
};
|
|
3194
3323
|
user: Record<string, any> & {
|
|
3195
3324
|
id: string;
|
|
@@ -3226,6 +3355,7 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3226
3355
|
}, {
|
|
3227
3356
|
savedBy?: string | undefined;
|
|
3228
3357
|
savedAt?: string | undefined;
|
|
3358
|
+
platformSignIn?: string | undefined;
|
|
3229
3359
|
operator?: string | undefined;
|
|
3230
3360
|
policy: SignInPolicy;
|
|
3231
3361
|
effective: SignInPolicy;
|
|
@@ -3243,7 +3373,12 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3243
3373
|
expiresAt: Date;
|
|
3244
3374
|
token: string;
|
|
3245
3375
|
ipAddress?: string | null | undefined;
|
|
3246
|
-
userAgent
|
|
3376
|
+
userAgent? /**
|
|
3377
|
+
* A sign-in provider the platform adds for people who already have an account: an OpenID Connect provider that never
|
|
3378
|
+
* signs anyone up. Defaults to the one the platform passes in `PROTOBASE_SIGN_IN_ISSUER`, `PROTOBASE_SIGN_IN_CLIENT_ID`
|
|
3379
|
+
* and `PROTOBASE_SIGN_IN_CLIENT_SECRET` (see `readPlatformSignIn`), when set; `false` turns it off whatever the
|
|
3380
|
+
* environment says. Left out when `socialProviders` has a provider with the same id.
|
|
3381
|
+
*/ : string | null | undefined;
|
|
3247
3382
|
};
|
|
3248
3383
|
user: Record<string, any> & {
|
|
3249
3384
|
id: string;
|
|
@@ -3265,7 +3400,7 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3265
3400
|
twoFactor: boolean;
|
|
3266
3401
|
authenticatorApp: boolean;
|
|
3267
3402
|
};
|
|
3268
|
-
missing: ("
|
|
3403
|
+
missing: ("twoFactor" | "passkey")[];
|
|
3269
3404
|
}>;
|
|
3270
3405
|
};
|
|
3271
3406
|
hooks: {
|
|
@@ -3278,14 +3413,17 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3278
3413
|
id: "protobase-staff-sign-in";
|
|
3279
3414
|
schema: {
|
|
3280
3415
|
readonly staffSignIn: {
|
|
3416
|
+
readonly modelName: "staff_sign_in";
|
|
3281
3417
|
readonly fields: {
|
|
3282
3418
|
readonly userId: {
|
|
3283
3419
|
readonly type: "string";
|
|
3284
3420
|
readonly required: true;
|
|
3421
|
+
readonly fieldName: "user_id";
|
|
3285
3422
|
};
|
|
3286
3423
|
readonly userEmail: {
|
|
3287
3424
|
readonly type: "string";
|
|
3288
3425
|
readonly required: true;
|
|
3426
|
+
readonly fieldName: "user_email";
|
|
3289
3427
|
};
|
|
3290
3428
|
readonly staff: {
|
|
3291
3429
|
readonly type: "string";
|
|
@@ -3294,10 +3432,12 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3294
3432
|
readonly staffName: {
|
|
3295
3433
|
readonly type: "string";
|
|
3296
3434
|
readonly required: false;
|
|
3435
|
+
readonly fieldName: "staff_name";
|
|
3297
3436
|
};
|
|
3298
3437
|
readonly staffSubject: {
|
|
3299
3438
|
readonly type: "string";
|
|
3300
3439
|
readonly required: true;
|
|
3440
|
+
readonly fieldName: "staff_subject";
|
|
3301
3441
|
};
|
|
3302
3442
|
readonly issuer: {
|
|
3303
3443
|
readonly type: "string";
|
|
@@ -3310,18 +3450,22 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3310
3450
|
readonly sessionId: {
|
|
3311
3451
|
readonly type: "string";
|
|
3312
3452
|
readonly required: true;
|
|
3453
|
+
readonly fieldName: "session_id";
|
|
3313
3454
|
};
|
|
3314
3455
|
readonly startedAt: {
|
|
3315
3456
|
readonly type: "date";
|
|
3316
3457
|
readonly required: true;
|
|
3458
|
+
readonly fieldName: "started_at";
|
|
3317
3459
|
};
|
|
3318
3460
|
readonly expiresAt: {
|
|
3319
3461
|
readonly type: "date";
|
|
3320
3462
|
readonly required: true;
|
|
3463
|
+
readonly fieldName: "expires_at";
|
|
3321
3464
|
};
|
|
3322
3465
|
readonly endedAt: {
|
|
3323
3466
|
readonly type: "date";
|
|
3324
3467
|
readonly required: false;
|
|
3468
|
+
readonly fieldName: "ended_at";
|
|
3325
3469
|
};
|
|
3326
3470
|
};
|
|
3327
3471
|
};
|
|
@@ -3339,7 +3483,12 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3339
3483
|
expiresAt: Date;
|
|
3340
3484
|
token: string;
|
|
3341
3485
|
ipAddress?: string | null | undefined;
|
|
3342
|
-
userAgent
|
|
3486
|
+
userAgent? /**
|
|
3487
|
+
* A sign-in provider the platform adds for people who already have an account: an OpenID Connect provider that never
|
|
3488
|
+
* signs anyone up. Defaults to the one the platform passes in `PROTOBASE_SIGN_IN_ISSUER`, `PROTOBASE_SIGN_IN_CLIENT_ID`
|
|
3489
|
+
* and `PROTOBASE_SIGN_IN_CLIENT_SECRET` (see `readPlatformSignIn`), when set; `false` turns it off whatever the
|
|
3490
|
+
* environment says. Left out when `socialProviders` has a provider with the same id.
|
|
3491
|
+
*/ : string | null | undefined;
|
|
3343
3492
|
};
|
|
3344
3493
|
user: Record<string, any> & {
|
|
3345
3494
|
id: string;
|
|
@@ -3367,7 +3516,12 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3367
3516
|
expiresAt: Date;
|
|
3368
3517
|
token: string;
|
|
3369
3518
|
ipAddress?: string | null | undefined;
|
|
3370
|
-
userAgent
|
|
3519
|
+
userAgent? /**
|
|
3520
|
+
* A sign-in provider the platform adds for people who already have an account: an OpenID Connect provider that never
|
|
3521
|
+
* signs anyone up. Defaults to the one the platform passes in `PROTOBASE_SIGN_IN_ISSUER`, `PROTOBASE_SIGN_IN_CLIENT_ID`
|
|
3522
|
+
* and `PROTOBASE_SIGN_IN_CLIENT_SECRET` (see `readPlatformSignIn`), when set; `false` turns it off whatever the
|
|
3523
|
+
* environment says. Left out when `socialProviders` has a provider with the same id.
|
|
3524
|
+
*/ : string | null | undefined;
|
|
3371
3525
|
};
|
|
3372
3526
|
user: Record<string, any> & {
|
|
3373
3527
|
id: string;
|
|
@@ -3396,7 +3550,12 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3396
3550
|
expiresAt: Date;
|
|
3397
3551
|
token: string;
|
|
3398
3552
|
ipAddress?: string | null | undefined;
|
|
3399
|
-
userAgent
|
|
3553
|
+
userAgent? /**
|
|
3554
|
+
* A sign-in provider the platform adds for people who already have an account: an OpenID Connect provider that never
|
|
3555
|
+
* signs anyone up. Defaults to the one the platform passes in `PROTOBASE_SIGN_IN_ISSUER`, `PROTOBASE_SIGN_IN_CLIENT_ID`
|
|
3556
|
+
* and `PROTOBASE_SIGN_IN_CLIENT_SECRET` (see `readPlatformSignIn`), when set; `false` turns it off whatever the
|
|
3557
|
+
* environment says. Left out when `socialProviders` has a provider with the same id.
|
|
3558
|
+
*/ : string | null | undefined;
|
|
3400
3559
|
};
|
|
3401
3560
|
user: Record<string, any> & {
|
|
3402
3561
|
id: string;
|
|
@@ -3420,7 +3579,12 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3420
3579
|
expiresAt: Date;
|
|
3421
3580
|
token: string;
|
|
3422
3581
|
ipAddress?: string | null | undefined;
|
|
3423
|
-
userAgent
|
|
3582
|
+
userAgent? /**
|
|
3583
|
+
* A sign-in provider the platform adds for people who already have an account: an OpenID Connect provider that never
|
|
3584
|
+
* signs anyone up. Defaults to the one the platform passes in `PROTOBASE_SIGN_IN_ISSUER`, `PROTOBASE_SIGN_IN_CLIENT_ID`
|
|
3585
|
+
* and `PROTOBASE_SIGN_IN_CLIENT_SECRET` (see `readPlatformSignIn`), when set; `false` turns it off whatever the
|
|
3586
|
+
* environment says. Left out when `socialProviders` has a provider with the same id.
|
|
3587
|
+
*/ : string | null | undefined;
|
|
3424
3588
|
};
|
|
3425
3589
|
user: Record<string, any> & {
|
|
3426
3590
|
id: string;
|
|
@@ -3443,7 +3607,12 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3443
3607
|
expiresAt: Date;
|
|
3444
3608
|
token: string;
|
|
3445
3609
|
ipAddress?: string | null | undefined;
|
|
3446
|
-
userAgent
|
|
3610
|
+
userAgent? /**
|
|
3611
|
+
* A sign-in provider the platform adds for people who already have an account: an OpenID Connect provider that never
|
|
3612
|
+
* signs anyone up. Defaults to the one the platform passes in `PROTOBASE_SIGN_IN_ISSUER`, `PROTOBASE_SIGN_IN_CLIENT_ID`
|
|
3613
|
+
* and `PROTOBASE_SIGN_IN_CLIENT_SECRET` (see `readPlatformSignIn`), when set; `false` turns it off whatever the
|
|
3614
|
+
* environment says. Left out when `socialProviders` has a provider with the same id.
|
|
3615
|
+
*/ : string | null | undefined;
|
|
3447
3616
|
};
|
|
3448
3617
|
user: Record<string, any> & {
|
|
3449
3618
|
id: string;
|
|
@@ -3556,9 +3725,6 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3556
3725
|
handler: () => void;
|
|
3557
3726
|
};
|
|
3558
3727
|
};
|
|
3559
|
-
account?: {
|
|
3560
|
-
encryptOAuthTokens: true;
|
|
3561
|
-
} | undefined;
|
|
3562
3728
|
socialProviders?: import("better-auth").SocialProviders | undefined;
|
|
3563
3729
|
appName: string;
|
|
3564
3730
|
database: any;
|
|
@@ -3585,6 +3751,10 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
|
|
|
3585
3751
|
passwordReset: boolean;
|
|
3586
3752
|
socialProviders: string[];
|
|
3587
3753
|
operator: string | undefined;
|
|
3754
|
+
platformSignIn: {
|
|
3755
|
+
provider: string;
|
|
3756
|
+
name: string;
|
|
3757
|
+
} | undefined;
|
|
3588
3758
|
};
|
|
3589
3759
|
export type AdminAuth = ReturnType<typeof createAuth>;
|
|
3590
3760
|
//#endregion
|
|
@@ -2,17 +2,20 @@ import { readMailSettings } from "../mail/mail-settings.js";
|
|
|
2
2
|
import { smtpMailer } from "../mail/smtp-mailer.js";
|
|
3
3
|
import { readOperatorSettings, resolveOperator } from "./operator-provider.js";
|
|
4
4
|
import { passwordResetOptions } from "./password-reset.js";
|
|
5
|
+
import { platformSignInFor, platformSignInProvider, readPlatformSignIn, resolvePlatformSignIn } from "./platform-sign-in.js";
|
|
5
6
|
import { signInPolicyPlugin } from "./policy-plugin.js";
|
|
6
7
|
import { emailCodeOptions, twoFactorCodeOptions, unusedEmailCodePaths } from "./sign-in-mail.js";
|
|
8
|
+
import { coreNames, pluginNames } from "./snake-case-names.js";
|
|
7
9
|
import { staffSignInPlugin } from "./staff-plugin.js";
|
|
8
10
|
import { twoFactorAfterPasswordOrCode } from "./two-factor-challenge.js";
|
|
9
11
|
import { passkey } from "@better-auth/passkey";
|
|
10
12
|
import { APIError } from "better-auth/api";
|
|
11
13
|
import { betterAuth } from "better-auth";
|
|
12
|
-
import { admin, emailOTP, jwt } from "better-auth/plugins";
|
|
14
|
+
import { admin, emailOTP, genericOAuth, jwt } from "better-auth/plugins";
|
|
13
15
|
import { adminAc, userAc } from "better-auth/plugins/admin/access";
|
|
14
16
|
//#region src/better-auth/create-auth.ts
|
|
15
17
|
const platformOperator = () => readOperatorSettings(globalThis.process?.env ?? {});
|
|
18
|
+
const platformSignInSettings = () => readPlatformSignIn(globalThis.process?.env ?? {});
|
|
16
19
|
const platformMailer = () => {
|
|
17
20
|
const settings = readMailSettings(globalThis.process?.env ?? {});
|
|
18
21
|
return settings && smtpMailer(settings);
|
|
@@ -33,9 +36,13 @@ const normalizeRoles = (roles = ["admin", "user"]) => {
|
|
|
33
36
|
return ["admin", ...new Set(roles.filter((role) => role !== "admin"))];
|
|
34
37
|
};
|
|
35
38
|
const adminImpersonationPaths = ["/admin/impersonate-user", "/admin/stop-impersonating"];
|
|
36
|
-
/**
|
|
37
|
-
|
|
39
|
+
/**
|
|
40
|
+
* The options `createAuth` gives Better Auth, with the roles, default role, mailer, operator provider and platform
|
|
41
|
+
* sign-in provider already resolved.
|
|
42
|
+
*/
|
|
43
|
+
const betterAuthOptions = (options, { roles, defaultRole, mailer, operator, platformSignIn }) => {
|
|
38
44
|
const secure = options.baseURL.startsWith("https://");
|
|
45
|
+
const signIn = platformSignInFor(platformSignIn, Object.keys(options.socialProviders ?? {}));
|
|
39
46
|
return {
|
|
40
47
|
appName: options.appName ?? "Protobase",
|
|
41
48
|
database: options.database,
|
|
@@ -54,13 +61,22 @@ const betterAuthOptions = (options, { roles, defaultRole, mailer, operator }) =>
|
|
|
54
61
|
...mailer && passwordResetOptions(mailer)
|
|
55
62
|
},
|
|
56
63
|
...options.socialProviders && { socialProviders: options.socialProviders },
|
|
57
|
-
|
|
64
|
+
user: coreNames.user,
|
|
65
|
+
session: coreNames.session,
|
|
66
|
+
verification: coreNames.verification,
|
|
67
|
+
account: {
|
|
68
|
+
...coreNames.account,
|
|
69
|
+
accountLinking: { allowDifferentEmails: true },
|
|
70
|
+
...options.encryptOAuthTokens && { encryptOAuthTokens: true }
|
|
71
|
+
},
|
|
58
72
|
plugins: [
|
|
59
73
|
admin({
|
|
74
|
+
schema: pluginNames.admin,
|
|
60
75
|
defaultRole: defaultRole ?? "unassigned",
|
|
61
76
|
roles: Object.fromEntries(roles.map((role) => [role, role === "admin" ? adminAc : userAc]))
|
|
62
77
|
}),
|
|
63
78
|
jwt({
|
|
79
|
+
schema: pluginNames.jwt,
|
|
64
80
|
jwt: {
|
|
65
81
|
expirationTime: tokenLifetime,
|
|
66
82
|
issuer: options.baseURL,
|
|
@@ -73,15 +89,21 @@ const betterAuthOptions = (options, { roles, defaultRole, mailer, operator }) =>
|
|
|
73
89
|
disableSettingJwtHeader: true
|
|
74
90
|
}),
|
|
75
91
|
twoFactorAfterPasswordOrCode({
|
|
92
|
+
schema: pluginNames.twoFactor,
|
|
76
93
|
allowPasswordless: true,
|
|
77
94
|
...mailer && { otpOptions: twoFactorCodeOptions(mailer) }
|
|
78
95
|
}),
|
|
79
|
-
passkey(),
|
|
96
|
+
passkey({ schema: pluginNames.passkey }),
|
|
80
97
|
...mailer ? [emailOTP(emailCodeOptions(mailer))] : [],
|
|
98
|
+
...signIn ? [genericOAuth({ config: [platformSignInProvider(signIn)] })] : [],
|
|
81
99
|
signInPolicyPlugin({
|
|
82
100
|
mail: Boolean(mailer),
|
|
83
101
|
socialProviders: Object.keys(options.socialProviders ?? {}),
|
|
84
|
-
...operator && { operator: operator.name }
|
|
102
|
+
...operator && { operator: operator.name },
|
|
103
|
+
...signIn && { platformSignIn: {
|
|
104
|
+
provider: signIn.provider,
|
|
105
|
+
name: signIn.name
|
|
106
|
+
} }
|
|
85
107
|
}),
|
|
86
108
|
staffSignInPlugin({
|
|
87
109
|
...operator && { operator },
|
|
@@ -134,20 +156,27 @@ const createAuth = (options) => {
|
|
|
134
156
|
const mailer = options.mailer === void 0 ? platformMailer() : options.mailer || void 0;
|
|
135
157
|
const provider = options.operator === void 0 ? platformOperator() : options.operator || void 0;
|
|
136
158
|
const operator = provider && resolveOperator(provider);
|
|
159
|
+
const signInSettings = options.signInProvider === void 0 ? platformSignInSettings() : options.signInProvider || void 0;
|
|
160
|
+
const socialProviders = Object.keys(options.socialProviders ?? {});
|
|
161
|
+
const platformSignIn = platformSignInFor(signInSettings && resolvePlatformSignIn(signInSettings), socialProviders);
|
|
137
162
|
const auth = betterAuth(betterAuthOptions(options, {
|
|
138
163
|
roles,
|
|
139
164
|
defaultRole,
|
|
140
165
|
mailer,
|
|
141
|
-
operator
|
|
166
|
+
operator,
|
|
167
|
+
platformSignIn
|
|
142
168
|
}));
|
|
143
|
-
const socialProviders = Object.keys(options.socialProviders ?? {});
|
|
144
169
|
return Object.assign(auth, {
|
|
145
170
|
roles,
|
|
146
171
|
defaultRole,
|
|
147
172
|
mail: Boolean(mailer),
|
|
148
173
|
passwordReset: Boolean(mailer),
|
|
149
174
|
socialProviders,
|
|
150
|
-
operator: operator?.name
|
|
175
|
+
operator: operator?.name,
|
|
176
|
+
platformSignIn: platformSignIn && {
|
|
177
|
+
provider: platformSignIn.provider,
|
|
178
|
+
name: platformSignIn.name
|
|
179
|
+
}
|
|
151
180
|
});
|
|
152
181
|
};
|
|
153
182
|
//#endregion
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import "better-auth/plugins";
|
|
2
|
+
//#region src/better-auth/platform-sign-in.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* A sign-in provider the platform adds to the app, for people who already have an account: any OpenID Connect
|
|
5
|
+
* provider, with this app registered as a confidential client whose redirect URI is
|
|
6
|
+
* `{baseURL}/api/auth/callback/{provider}`. It never creates accounts.
|
|
7
|
+
*/
|
|
8
|
+
export type PlatformSignIn = {
|
|
9
|
+
/** The provider's issuer URL; its settings are read from `{issuer}/.well-known/openid-configuration`. */
|
|
10
|
+
issuer: string;
|
|
11
|
+
clientId: string;
|
|
12
|
+
clientSecret: string;
|
|
13
|
+
/**
|
|
14
|
+
* The id of the provider: the button, the callback path, and the namespace of the linked accounts. Default `oidc`.
|
|
15
|
+
* Use `github` only when the provider's `sub` is the GitHub user id, so its accounts are those of Better Auth's own
|
|
16
|
+
* GitHub provider.
|
|
17
|
+
*/
|
|
18
|
+
provider?: string;
|
|
19
|
+
/** Shown on the sign-in page as "Continue with {name}". Default `GitHub` for the `github` provider, `SSO` otherwise. */
|
|
20
|
+
name?: string;
|
|
21
|
+
/** Scopes asked for besides `openid email profile`. */
|
|
22
|
+
scopes?: string[];
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* The provider the platform passes in `PROTOBASE_SIGN_IN_ISSUER`, `PROTOBASE_SIGN_IN_CLIENT_ID` and
|
|
26
|
+
* `PROTOBASE_SIGN_IN_CLIENT_SECRET` (with `PROTOBASE_SIGN_IN_PROVIDER` and `PROTOBASE_SIGN_IN_NAME` optional);
|
|
27
|
+
* `undefined` when none of the three is set. Some but not all of them stops the server at startup.
|
|
28
|
+
*/
|
|
29
|
+
export declare const readPlatformSignIn: (env: Record<string, string | undefined>) => PlatformSignIn | undefined;
|
|
30
|
+
//#endregion
|