@absolutejs/auth 0.26.0-beta.3 → 0.26.0-beta.5
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/audit/types.d.ts +1 -1
- package/dist/index.d.ts +5531 -440
- package/dist/index.js +2492 -1108
- package/dist/index.js.map +30 -7
- package/dist/organizations/config.d.ts +46 -0
- package/dist/organizations/inMemoryOrganizationStore.d.ts +2 -0
- package/dist/organizations/operations.d.ts +32 -0
- package/dist/organizations/postgresOrganizationStore.d.ts +412 -0
- package/dist/organizations/routes.d.ts +299 -0
- package/dist/organizations/types.d.ts +44 -0
- package/dist/passwordless/config.d.ts +42 -0
- package/dist/passwordless/inMemoryPasswordlessTokenStore.d.ts +2 -0
- package/dist/passwordless/postgresPasswordlessTokenStore.d.ts +66 -0
- package/dist/passwordless/routes.d.ts +163 -0
- package/dist/passwordless/types.d.ts +9 -0
- package/dist/portal/config.d.ts +34 -0
- package/dist/portal/inMemorySetupSessionStore.d.ts +2 -0
- package/dist/portal/operations.d.ts +10 -0
- package/dist/portal/postgresSetupSessionStore.d.ts +140 -0
- package/dist/portal/routes.d.ts +160 -0
- package/dist/portal/types.d.ts +16 -0
- package/dist/roles/config.d.ts +27 -0
- package/dist/roles/inMemoryRoleStore.d.ts +2 -0
- package/dist/roles/operations.d.ts +8 -0
- package/dist/roles/postgresRoleStore.d.ts +102 -0
- package/dist/roles/resolver.d.ts +17 -0
- package/dist/roles/routes.d.ts +106 -0
- package/dist/roles/types.d.ts +14 -0
- package/dist/types.d.ts +29 -0
- package/dist/webhooks/config.d.ts +21 -0
- package/dist/webhooks/dispatcher.d.ts +3 -0
- package/dist/webhooks/sign.d.ts +11 -0
- package/dist/webhooks/types.d.ts +11 -0
- package/package.json +1 -1
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { type AnyPgDatabase } from '../stores/postgres';
|
|
2
|
+
import type { SetupCapability, SetupSessionStore } from './types';
|
|
3
|
+
export declare const setupSessionsTable: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
4
|
+
name: "auth_setup_sessions";
|
|
5
|
+
schema: undefined;
|
|
6
|
+
columns: {
|
|
7
|
+
capabilities: import("drizzle-orm/pg-core").PgColumn<{
|
|
8
|
+
name: "capabilities";
|
|
9
|
+
tableName: "auth_setup_sessions";
|
|
10
|
+
dataType: "json";
|
|
11
|
+
columnType: "PgJsonb";
|
|
12
|
+
data: SetupCapability[];
|
|
13
|
+
driverParam: unknown;
|
|
14
|
+
notNull: true;
|
|
15
|
+
hasDefault: true;
|
|
16
|
+
isPrimaryKey: false;
|
|
17
|
+
isAutoincrement: false;
|
|
18
|
+
hasRuntimeDefault: false;
|
|
19
|
+
enumValues: undefined;
|
|
20
|
+
baseColumn: never;
|
|
21
|
+
identity: undefined;
|
|
22
|
+
generated: undefined;
|
|
23
|
+
}, {}, {
|
|
24
|
+
$type: SetupCapability[];
|
|
25
|
+
}>;
|
|
26
|
+
created_at_ms: import("drizzle-orm/pg-core").PgColumn<{
|
|
27
|
+
name: "created_at_ms";
|
|
28
|
+
tableName: "auth_setup_sessions";
|
|
29
|
+
dataType: "number";
|
|
30
|
+
columnType: "PgBigInt53";
|
|
31
|
+
data: number;
|
|
32
|
+
driverParam: string | number;
|
|
33
|
+
notNull: true;
|
|
34
|
+
hasDefault: false;
|
|
35
|
+
isPrimaryKey: false;
|
|
36
|
+
isAutoincrement: false;
|
|
37
|
+
hasRuntimeDefault: false;
|
|
38
|
+
enumValues: undefined;
|
|
39
|
+
baseColumn: never;
|
|
40
|
+
identity: undefined;
|
|
41
|
+
generated: undefined;
|
|
42
|
+
}, {}, {}>;
|
|
43
|
+
created_by: import("drizzle-orm/pg-core").PgColumn<{
|
|
44
|
+
name: "created_by";
|
|
45
|
+
tableName: "auth_setup_sessions";
|
|
46
|
+
dataType: "string";
|
|
47
|
+
columnType: "PgVarchar";
|
|
48
|
+
data: string;
|
|
49
|
+
driverParam: string;
|
|
50
|
+
notNull: false;
|
|
51
|
+
hasDefault: false;
|
|
52
|
+
isPrimaryKey: false;
|
|
53
|
+
isAutoincrement: false;
|
|
54
|
+
hasRuntimeDefault: false;
|
|
55
|
+
enumValues: [string, ...string[]];
|
|
56
|
+
baseColumn: never;
|
|
57
|
+
identity: undefined;
|
|
58
|
+
generated: undefined;
|
|
59
|
+
}, {}, {
|
|
60
|
+
length: 255;
|
|
61
|
+
}>;
|
|
62
|
+
expires_at_ms: import("drizzle-orm/pg-core").PgColumn<{
|
|
63
|
+
name: "expires_at_ms";
|
|
64
|
+
tableName: "auth_setup_sessions";
|
|
65
|
+
dataType: "number";
|
|
66
|
+
columnType: "PgBigInt53";
|
|
67
|
+
data: number;
|
|
68
|
+
driverParam: string | number;
|
|
69
|
+
notNull: true;
|
|
70
|
+
hasDefault: false;
|
|
71
|
+
isPrimaryKey: false;
|
|
72
|
+
isAutoincrement: false;
|
|
73
|
+
hasRuntimeDefault: false;
|
|
74
|
+
enumValues: undefined;
|
|
75
|
+
baseColumn: never;
|
|
76
|
+
identity: undefined;
|
|
77
|
+
generated: undefined;
|
|
78
|
+
}, {}, {}>;
|
|
79
|
+
organization_id: import("drizzle-orm/pg-core").PgColumn<{
|
|
80
|
+
name: "organization_id";
|
|
81
|
+
tableName: "auth_setup_sessions";
|
|
82
|
+
dataType: "string";
|
|
83
|
+
columnType: "PgVarchar";
|
|
84
|
+
data: string;
|
|
85
|
+
driverParam: string;
|
|
86
|
+
notNull: true;
|
|
87
|
+
hasDefault: false;
|
|
88
|
+
isPrimaryKey: false;
|
|
89
|
+
isAutoincrement: false;
|
|
90
|
+
hasRuntimeDefault: false;
|
|
91
|
+
enumValues: [string, ...string[]];
|
|
92
|
+
baseColumn: never;
|
|
93
|
+
identity: undefined;
|
|
94
|
+
generated: undefined;
|
|
95
|
+
}, {}, {
|
|
96
|
+
length: 255;
|
|
97
|
+
}>;
|
|
98
|
+
setup_session_id: import("drizzle-orm/pg-core").PgColumn<{
|
|
99
|
+
name: "setup_session_id";
|
|
100
|
+
tableName: "auth_setup_sessions";
|
|
101
|
+
dataType: "string";
|
|
102
|
+
columnType: "PgVarchar";
|
|
103
|
+
data: string;
|
|
104
|
+
driverParam: string;
|
|
105
|
+
notNull: true;
|
|
106
|
+
hasDefault: false;
|
|
107
|
+
isPrimaryKey: true;
|
|
108
|
+
isAutoincrement: false;
|
|
109
|
+
hasRuntimeDefault: false;
|
|
110
|
+
enumValues: [string, ...string[]];
|
|
111
|
+
baseColumn: never;
|
|
112
|
+
identity: undefined;
|
|
113
|
+
generated: undefined;
|
|
114
|
+
}, {}, {
|
|
115
|
+
length: 255;
|
|
116
|
+
}>;
|
|
117
|
+
token_hash: import("drizzle-orm/pg-core").PgColumn<{
|
|
118
|
+
name: "token_hash";
|
|
119
|
+
tableName: "auth_setup_sessions";
|
|
120
|
+
dataType: "string";
|
|
121
|
+
columnType: "PgVarchar";
|
|
122
|
+
data: string;
|
|
123
|
+
driverParam: string;
|
|
124
|
+
notNull: true;
|
|
125
|
+
hasDefault: false;
|
|
126
|
+
isPrimaryKey: false;
|
|
127
|
+
isAutoincrement: false;
|
|
128
|
+
hasRuntimeDefault: false;
|
|
129
|
+
enumValues: [string, ...string[]];
|
|
130
|
+
baseColumn: never;
|
|
131
|
+
identity: undefined;
|
|
132
|
+
generated: undefined;
|
|
133
|
+
}, {}, {
|
|
134
|
+
length: 255;
|
|
135
|
+
}>;
|
|
136
|
+
};
|
|
137
|
+
dialect: "pg";
|
|
138
|
+
}>;
|
|
139
|
+
export declare const createNeonSetupSessionStore: (databaseUrl: string) => SetupSessionStore;
|
|
140
|
+
export declare const createPostgresSetupSessionStore: (db: AnyPgDatabase) => SetupSessionStore;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { Elysia } from 'elysia';
|
|
2
|
+
import { type PortalRouteProps } from './config';
|
|
3
|
+
export declare const portalRoutes: ({ emit, onScimTokenCreated, onSsoConnectionConfigured, portalRoute, scimRoute, scimTokenStore, setupSessionStore, ssoConnectionStore, ssoRoute }: PortalRouteProps) => Elysia<"", {
|
|
4
|
+
decorator: {};
|
|
5
|
+
store: {};
|
|
6
|
+
derive: {};
|
|
7
|
+
resolve: {};
|
|
8
|
+
}, {
|
|
9
|
+
typebox: {};
|
|
10
|
+
error: {};
|
|
11
|
+
}, {
|
|
12
|
+
schema: {};
|
|
13
|
+
standaloneSchema: {};
|
|
14
|
+
macro: {};
|
|
15
|
+
macroFn: {};
|
|
16
|
+
parser: {};
|
|
17
|
+
response: {};
|
|
18
|
+
}, {
|
|
19
|
+
[x: string]: {
|
|
20
|
+
session: {
|
|
21
|
+
get: {
|
|
22
|
+
body: unknown;
|
|
23
|
+
params: {};
|
|
24
|
+
query: unknown;
|
|
25
|
+
headers: unknown;
|
|
26
|
+
response: {
|
|
27
|
+
200: {
|
|
28
|
+
readonly capabilities: import("./types").SetupCapability[];
|
|
29
|
+
readonly configured: {
|
|
30
|
+
readonly oidc: boolean;
|
|
31
|
+
readonly saml: boolean;
|
|
32
|
+
};
|
|
33
|
+
readonly expiresAt: number;
|
|
34
|
+
readonly oidc: {
|
|
35
|
+
redirectUri: string;
|
|
36
|
+
} | undefined;
|
|
37
|
+
readonly organizationId: string;
|
|
38
|
+
readonly saml: {
|
|
39
|
+
acsUrl: string;
|
|
40
|
+
entityId: string;
|
|
41
|
+
metadataUrl: string;
|
|
42
|
+
} | undefined;
|
|
43
|
+
readonly scim: {
|
|
44
|
+
baseUrl: string;
|
|
45
|
+
} | undefined;
|
|
46
|
+
};
|
|
47
|
+
401: "Invalid or expired setup link";
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
} & {
|
|
53
|
+
[x: string]: {
|
|
54
|
+
connection: {
|
|
55
|
+
saml: {
|
|
56
|
+
put: {
|
|
57
|
+
body: {
|
|
58
|
+
idpSloUrl?: string | undefined;
|
|
59
|
+
idpEntityId: string;
|
|
60
|
+
idpSsoUrl: string;
|
|
61
|
+
idpX509Cert: string;
|
|
62
|
+
};
|
|
63
|
+
params: {};
|
|
64
|
+
query: unknown;
|
|
65
|
+
headers: unknown;
|
|
66
|
+
response: {
|
|
67
|
+
200: {
|
|
68
|
+
readonly configured: true;
|
|
69
|
+
readonly type: "saml";
|
|
70
|
+
};
|
|
71
|
+
401: "Invalid or expired setup link";
|
|
72
|
+
403: "This setup link cannot configure SAML";
|
|
73
|
+
422: {
|
|
74
|
+
type: "validation";
|
|
75
|
+
on: string;
|
|
76
|
+
summary?: string;
|
|
77
|
+
message?: string;
|
|
78
|
+
found?: unknown;
|
|
79
|
+
property?: string;
|
|
80
|
+
expected?: string;
|
|
81
|
+
};
|
|
82
|
+
501: "SSO is not configured";
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
} & {
|
|
89
|
+
[x: string]: {
|
|
90
|
+
connection: {
|
|
91
|
+
oidc: {
|
|
92
|
+
put: {
|
|
93
|
+
body: {
|
|
94
|
+
redirectUri?: string | undefined;
|
|
95
|
+
scopes?: string[] | undefined;
|
|
96
|
+
issuer: string;
|
|
97
|
+
clientId: string;
|
|
98
|
+
clientSecret: string;
|
|
99
|
+
};
|
|
100
|
+
params: {};
|
|
101
|
+
query: unknown;
|
|
102
|
+
headers: unknown;
|
|
103
|
+
response: {
|
|
104
|
+
200: {
|
|
105
|
+
readonly configured: true;
|
|
106
|
+
readonly type: "oidc";
|
|
107
|
+
};
|
|
108
|
+
401: "Invalid or expired setup link";
|
|
109
|
+
403: "This setup link cannot configure OIDC";
|
|
110
|
+
422: {
|
|
111
|
+
type: "validation";
|
|
112
|
+
on: string;
|
|
113
|
+
summary?: string;
|
|
114
|
+
message?: string;
|
|
115
|
+
found?: unknown;
|
|
116
|
+
property?: string;
|
|
117
|
+
expected?: string;
|
|
118
|
+
};
|
|
119
|
+
501: "SSO is not configured";
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
} & {
|
|
126
|
+
[x: string]: {
|
|
127
|
+
scim: {
|
|
128
|
+
token: {
|
|
129
|
+
post: {
|
|
130
|
+
body: unknown;
|
|
131
|
+
params: {};
|
|
132
|
+
query: unknown;
|
|
133
|
+
headers: unknown;
|
|
134
|
+
response: {
|
|
135
|
+
200: {
|
|
136
|
+
readonly baseUrl: `${string}/${string}`;
|
|
137
|
+
readonly token: string;
|
|
138
|
+
readonly tokenId: string;
|
|
139
|
+
};
|
|
140
|
+
401: "Invalid or expired setup link";
|
|
141
|
+
403: "This setup link cannot configure SCIM";
|
|
142
|
+
501: "SCIM is not configured";
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
}, {
|
|
149
|
+
derive: {};
|
|
150
|
+
resolve: {};
|
|
151
|
+
schema: {};
|
|
152
|
+
standaloneSchema: {};
|
|
153
|
+
response: {};
|
|
154
|
+
}, {
|
|
155
|
+
derive: {};
|
|
156
|
+
resolve: {};
|
|
157
|
+
schema: {};
|
|
158
|
+
standaloneSchema: {};
|
|
159
|
+
response: {};
|
|
160
|
+
}>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { OrganizationId } from '../tenancy';
|
|
2
|
+
export type SetupCapability = 'scim' | 'sso_oidc' | 'sso_saml';
|
|
3
|
+
export type SetupSession = {
|
|
4
|
+
capabilities: SetupCapability[];
|
|
5
|
+
createdAt: number;
|
|
6
|
+
createdBy?: string;
|
|
7
|
+
expiresAt: number;
|
|
8
|
+
organizationId: OrganizationId;
|
|
9
|
+
setupSessionId: string;
|
|
10
|
+
tokenHash: string;
|
|
11
|
+
};
|
|
12
|
+
export type SetupSessionStore = {
|
|
13
|
+
deleteSetupSession: (setupSessionId: string) => Promise<void>;
|
|
14
|
+
getSetupSessionByTokenHash: (tokenHash: string) => Promise<SetupSession | undefined>;
|
|
15
|
+
saveSetupSession: (session: SetupSession) => Promise<void>;
|
|
16
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AuditEmitter } from '../audit/config';
|
|
2
|
+
import type { OrganizationMembership, OrganizationStore } from '../organizations/types';
|
|
3
|
+
import type { AuthSessionStore } from '../session/types';
|
|
4
|
+
import type { OrganizationId } from '../tenancy';
|
|
5
|
+
import type { RouteString } from '../types';
|
|
6
|
+
import type { RoleStore } from './types';
|
|
7
|
+
export declare const DEFAULT_ROLES_ROUTE: RouteString;
|
|
8
|
+
export type RolesConfig<UserType> = {
|
|
9
|
+
getUserId: (user: UserType) => string;
|
|
10
|
+
organizationStore: OrganizationStore;
|
|
11
|
+
roleStore: RoleStore;
|
|
12
|
+
canManageRoles?: (context: {
|
|
13
|
+
membership?: OrganizationMembership;
|
|
14
|
+
organizationId: OrganizationId;
|
|
15
|
+
user: UserType;
|
|
16
|
+
}) => boolean | Promise<boolean>;
|
|
17
|
+
onRolesAssigned?: (context: {
|
|
18
|
+
organizationId: OrganizationId;
|
|
19
|
+
roles: string[];
|
|
20
|
+
userId: string;
|
|
21
|
+
}) => void | Promise<void>;
|
|
22
|
+
rolesRoute?: RouteString;
|
|
23
|
+
};
|
|
24
|
+
export type RolesRouteProps<UserType> = RolesConfig<UserType> & {
|
|
25
|
+
authSessionStore?: AuthSessionStore<UserType>;
|
|
26
|
+
emit?: AuditEmitter;
|
|
27
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { OrganizationMembership, OrganizationStore } from '../organizations/types';
|
|
2
|
+
import type { OrganizationId } from '../tenancy';
|
|
3
|
+
export declare const setMemberRoles: ({ organizationId, organizationStore, roles, userId }: {
|
|
4
|
+
organizationId: OrganizationId;
|
|
5
|
+
organizationStore: OrganizationStore;
|
|
6
|
+
roles: string[];
|
|
7
|
+
userId: string;
|
|
8
|
+
}) => Promise<OrganizationMembership | undefined>;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { type AnyPgDatabase } from '../stores/postgres';
|
|
2
|
+
import type { RoleStore } from './types';
|
|
3
|
+
export declare const rolesTable: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
4
|
+
name: "auth_roles";
|
|
5
|
+
schema: undefined;
|
|
6
|
+
columns: {
|
|
7
|
+
created_at_ms: import("drizzle-orm/pg-core").PgColumn<{
|
|
8
|
+
name: "created_at_ms";
|
|
9
|
+
tableName: "auth_roles";
|
|
10
|
+
dataType: "number";
|
|
11
|
+
columnType: "PgBigInt53";
|
|
12
|
+
data: number;
|
|
13
|
+
driverParam: string | number;
|
|
14
|
+
notNull: true;
|
|
15
|
+
hasDefault: false;
|
|
16
|
+
isPrimaryKey: false;
|
|
17
|
+
isAutoincrement: false;
|
|
18
|
+
hasRuntimeDefault: false;
|
|
19
|
+
enumValues: undefined;
|
|
20
|
+
baseColumn: never;
|
|
21
|
+
identity: undefined;
|
|
22
|
+
generated: undefined;
|
|
23
|
+
}, {}, {}>;
|
|
24
|
+
organization_id: import("drizzle-orm/pg-core").PgColumn<{
|
|
25
|
+
name: "organization_id";
|
|
26
|
+
tableName: "auth_roles";
|
|
27
|
+
dataType: "string";
|
|
28
|
+
columnType: "PgVarchar";
|
|
29
|
+
data: string;
|
|
30
|
+
driverParam: string;
|
|
31
|
+
notNull: true;
|
|
32
|
+
hasDefault: true;
|
|
33
|
+
isPrimaryKey: false;
|
|
34
|
+
isAutoincrement: false;
|
|
35
|
+
hasRuntimeDefault: false;
|
|
36
|
+
enumValues: [string, ...string[]];
|
|
37
|
+
baseColumn: never;
|
|
38
|
+
identity: undefined;
|
|
39
|
+
generated: undefined;
|
|
40
|
+
}, {}, {
|
|
41
|
+
length: 255;
|
|
42
|
+
}>;
|
|
43
|
+
permissions: import("drizzle-orm/pg-core").PgColumn<{
|
|
44
|
+
name: "permissions";
|
|
45
|
+
tableName: "auth_roles";
|
|
46
|
+
dataType: "json";
|
|
47
|
+
columnType: "PgJsonb";
|
|
48
|
+
data: string[];
|
|
49
|
+
driverParam: unknown;
|
|
50
|
+
notNull: true;
|
|
51
|
+
hasDefault: true;
|
|
52
|
+
isPrimaryKey: false;
|
|
53
|
+
isAutoincrement: false;
|
|
54
|
+
hasRuntimeDefault: false;
|
|
55
|
+
enumValues: undefined;
|
|
56
|
+
baseColumn: never;
|
|
57
|
+
identity: undefined;
|
|
58
|
+
generated: undefined;
|
|
59
|
+
}, {}, {
|
|
60
|
+
$type: string[];
|
|
61
|
+
}>;
|
|
62
|
+
slug: import("drizzle-orm/pg-core").PgColumn<{
|
|
63
|
+
name: "slug";
|
|
64
|
+
tableName: "auth_roles";
|
|
65
|
+
dataType: "string";
|
|
66
|
+
columnType: "PgVarchar";
|
|
67
|
+
data: string;
|
|
68
|
+
driverParam: string;
|
|
69
|
+
notNull: true;
|
|
70
|
+
hasDefault: false;
|
|
71
|
+
isPrimaryKey: false;
|
|
72
|
+
isAutoincrement: false;
|
|
73
|
+
hasRuntimeDefault: false;
|
|
74
|
+
enumValues: [string, ...string[]];
|
|
75
|
+
baseColumn: never;
|
|
76
|
+
identity: undefined;
|
|
77
|
+
generated: undefined;
|
|
78
|
+
}, {}, {
|
|
79
|
+
length: 128;
|
|
80
|
+
}>;
|
|
81
|
+
updated_at_ms: import("drizzle-orm/pg-core").PgColumn<{
|
|
82
|
+
name: "updated_at_ms";
|
|
83
|
+
tableName: "auth_roles";
|
|
84
|
+
dataType: "number";
|
|
85
|
+
columnType: "PgBigInt53";
|
|
86
|
+
data: number;
|
|
87
|
+
driverParam: string | number;
|
|
88
|
+
notNull: true;
|
|
89
|
+
hasDefault: false;
|
|
90
|
+
isPrimaryKey: false;
|
|
91
|
+
isAutoincrement: false;
|
|
92
|
+
hasRuntimeDefault: false;
|
|
93
|
+
enumValues: undefined;
|
|
94
|
+
baseColumn: never;
|
|
95
|
+
identity: undefined;
|
|
96
|
+
generated: undefined;
|
|
97
|
+
}, {}, {}>;
|
|
98
|
+
};
|
|
99
|
+
dialect: "pg";
|
|
100
|
+
}>;
|
|
101
|
+
export declare const createNeonRoleStore: (databaseUrl: string) => RoleStore;
|
|
102
|
+
export declare const createPostgresRoleStore: (db: AnyPgDatabase) => RoleStore;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { OrganizationStore } from '../organizations/types';
|
|
2
|
+
import type { OrganizationId } from '../tenancy';
|
|
3
|
+
import type { RoleStore } from './types';
|
|
4
|
+
export declare const createMembershipPermissionResolver: <UserType>({ getUserId, organizationStore, roleStore }: {
|
|
5
|
+
getUserId: (user: UserType) => string;
|
|
6
|
+
organizationStore: OrganizationStore;
|
|
7
|
+
roleStore: RoleStore;
|
|
8
|
+
}) => ({ organizationId, permission, user }: {
|
|
9
|
+
organizationId?: OrganizationId;
|
|
10
|
+
permission: string;
|
|
11
|
+
user: UserType;
|
|
12
|
+
}) => Promise<boolean>;
|
|
13
|
+
export declare const resolvePermissions: ({ organizationId, roleStore, roles }: {
|
|
14
|
+
organizationId?: OrganizationId;
|
|
15
|
+
roleStore: RoleStore;
|
|
16
|
+
roles: string[];
|
|
17
|
+
}) => Promise<Set<string>>;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Elysia } from 'elysia';
|
|
2
|
+
import type { SessionRecord } from '../types';
|
|
3
|
+
import { type RolesRouteProps } from './config';
|
|
4
|
+
export declare const roleRoutes: <UserType>({ authSessionStore, canManageRoles, emit, getUserId, onRolesAssigned, organizationStore, roleStore, rolesRoute }: RolesRouteProps<UserType>) => Elysia<"", {
|
|
5
|
+
decorator: {};
|
|
6
|
+
store: {
|
|
7
|
+
session: SessionRecord<UserType>;
|
|
8
|
+
unregisteredSession: import("..").UnregisteredSessionRecord;
|
|
9
|
+
};
|
|
10
|
+
derive: {};
|
|
11
|
+
resolve: {};
|
|
12
|
+
}, {
|
|
13
|
+
typebox: {};
|
|
14
|
+
error: {};
|
|
15
|
+
}, {
|
|
16
|
+
schema: {};
|
|
17
|
+
standaloneSchema: {};
|
|
18
|
+
macro: {};
|
|
19
|
+
macroFn: {};
|
|
20
|
+
parser: {};
|
|
21
|
+
response: {};
|
|
22
|
+
}, {
|
|
23
|
+
[x: string]: {
|
|
24
|
+
":organizationId": {
|
|
25
|
+
get: {
|
|
26
|
+
body: unknown;
|
|
27
|
+
params: {
|
|
28
|
+
organizationId: string;
|
|
29
|
+
};
|
|
30
|
+
query: unknown;
|
|
31
|
+
headers: unknown;
|
|
32
|
+
response: {
|
|
33
|
+
200: {
|
|
34
|
+
readonly roles: readonly import("./types").Role[];
|
|
35
|
+
};
|
|
36
|
+
401: "Authentication required";
|
|
37
|
+
403: "Cannot manage roles";
|
|
38
|
+
422: {
|
|
39
|
+
type: "validation";
|
|
40
|
+
on: string;
|
|
41
|
+
summary?: string;
|
|
42
|
+
message?: string;
|
|
43
|
+
found?: unknown;
|
|
44
|
+
property?: string;
|
|
45
|
+
expected?: string;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
} & {
|
|
52
|
+
[x: string]: {
|
|
53
|
+
":organizationId": {
|
|
54
|
+
members: {
|
|
55
|
+
":userId": {
|
|
56
|
+
put: {
|
|
57
|
+
body: {
|
|
58
|
+
roles: string[];
|
|
59
|
+
};
|
|
60
|
+
params: {
|
|
61
|
+
userId: string;
|
|
62
|
+
organizationId: string;
|
|
63
|
+
};
|
|
64
|
+
query: unknown;
|
|
65
|
+
headers: unknown;
|
|
66
|
+
response: {
|
|
67
|
+
200: {
|
|
68
|
+
readonly roles: string[];
|
|
69
|
+
};
|
|
70
|
+
401: "Authentication required";
|
|
71
|
+
403: "Cannot manage roles";
|
|
72
|
+
404: "Membership not found";
|
|
73
|
+
422: {
|
|
74
|
+
type: "validation";
|
|
75
|
+
on: string;
|
|
76
|
+
summary?: string;
|
|
77
|
+
message?: string;
|
|
78
|
+
found?: unknown;
|
|
79
|
+
property?: string;
|
|
80
|
+
expected?: string;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
}, {
|
|
89
|
+
derive: {};
|
|
90
|
+
resolve: {};
|
|
91
|
+
schema: {};
|
|
92
|
+
standaloneSchema: {};
|
|
93
|
+
response: {};
|
|
94
|
+
}, {
|
|
95
|
+
derive: {};
|
|
96
|
+
resolve: {};
|
|
97
|
+
schema: {};
|
|
98
|
+
standaloneSchema: {};
|
|
99
|
+
response: {};
|
|
100
|
+
} & {
|
|
101
|
+
derive: {};
|
|
102
|
+
resolve: {};
|
|
103
|
+
schema: {};
|
|
104
|
+
standaloneSchema: {};
|
|
105
|
+
response: {};
|
|
106
|
+
}>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { OrganizationId } from '../tenancy';
|
|
2
|
+
export type Role = {
|
|
3
|
+
createdAt: number;
|
|
4
|
+
organizationId?: OrganizationId;
|
|
5
|
+
permissions: string[];
|
|
6
|
+
slug: string;
|
|
7
|
+
updatedAt: number;
|
|
8
|
+
};
|
|
9
|
+
export type RoleStore = {
|
|
10
|
+
deleteRole: (slug: string, organizationId?: OrganizationId) => Promise<void>;
|
|
11
|
+
getRole: (slug: string, organizationId?: OrganizationId) => Promise<Role | undefined>;
|
|
12
|
+
listRoles: (organizationId?: OrganizationId) => Promise<Role[]>;
|
|
13
|
+
saveRole: (role: Role) => Promise<void>;
|
|
14
|
+
};
|
package/dist/types.d.ts
CHANGED
|
@@ -9,11 +9,16 @@ import type { AuthIdentityConflict } from './errors';
|
|
|
9
9
|
import type { AuthHtmxConfig, AuthHtmxUser } from './htmx/types';
|
|
10
10
|
import type { LockoutConfig } from './lockout/config';
|
|
11
11
|
import type { MfaConfig } from './mfa/config';
|
|
12
|
+
import type { OrganizationsConfig } from './organizations/config';
|
|
13
|
+
import type { PasswordlessConfig } from './passwordless/config';
|
|
14
|
+
import type { PortalConfig } from './portal/config';
|
|
15
|
+
import type { RolesConfig } from './roles/config';
|
|
12
16
|
import type { ScimConfig } from './scim/config';
|
|
13
17
|
import type { SessionsConfig } from './session/sessionsConfig';
|
|
14
18
|
import type { AuthSessionStore } from './session/types';
|
|
15
19
|
import type { SSOConfig } from './sso/config';
|
|
16
20
|
import type { WebAuthnConfig } from './webauthn/config';
|
|
21
|
+
import type { WebhooksConfig } from './webhooks/config';
|
|
17
22
|
export type AuthIntent = 'login' | 'link_identity' | 'link_connector';
|
|
18
23
|
export type OAuth2ProviderClientConfiguration<Provider extends ProviderOption> = {
|
|
19
24
|
credentials: CredentialsFor<Provider>;
|
|
@@ -183,6 +188,11 @@ export type AuthConfig<UserType> = {
|
|
|
183
188
|
* mounts register / verify-email / login / reset-password routes that produce the
|
|
184
189
|
* same `SessionData<UserType>` as OAuth, transparent to `protectRoute`. */
|
|
185
190
|
credentials?: CredentialsConfig<UserType>;
|
|
191
|
+
/** Passwordless login: magic links + email/SMS OTP. When present, mounts the magic-link flow
|
|
192
|
+
* (if `onSendMagicLink` is set) and/or the OTP flow (if `onSendOtp` is set) under
|
|
193
|
+
* `{passwordlessRoute}`; each verify route resolves the email to a user and mints the same
|
|
194
|
+
* `SessionData<UserType>` as every other flow. */
|
|
195
|
+
passwordless?: PasswordlessConfig<UserType>;
|
|
186
196
|
/** Multi-factor auth (TOTP + backup codes). When present alongside `credentials`,
|
|
187
197
|
* `auth()` auto-wires the login MFA gate, mounts the enroll/challenge routes, and
|
|
188
198
|
* promotes the parked session once a factor is verified. */
|
|
@@ -203,6 +213,20 @@ export type AuthConfig<UserType> = {
|
|
|
203
213
|
* mounts `{scimRoute}/Users` (+ `/ServiceProviderConfig`) with per-org bearer-token auth via
|
|
204
214
|
* `scimTokenStore`, and maps SCIM resources to the consumer's user store through hooks. */
|
|
205
215
|
scim?: ScimConfig;
|
|
216
|
+
/** First-class multi-tenancy (the WorkOS model). When present, mounts organization +
|
|
217
|
+
* membership + invitation routes under `{organizationsRoute}`: list the caller's orgs, create
|
|
218
|
+
* one (caller becomes owner), invite/accept/revoke by email, and list/remove members. Ties the
|
|
219
|
+
* bare `organizationId` used by SSO/SCIM/RBAC into a real tenant model with org-scoped roles. */
|
|
220
|
+
organizations?: OrganizationsConfig<UserType>;
|
|
221
|
+
/** Admin portal — the WorkOS self-serve "setup link" model, headless. When present, mounts
|
|
222
|
+
* `{portalRoute}` endpoints a customer's IT admin (holding a scoped setup token from
|
|
223
|
+
* `createSetupSession`) calls to read the service-provider URLs and configure their own SSO
|
|
224
|
+
* connection / SCIM token. JSON contract, so the portal UI can be built in any framework. */
|
|
225
|
+
portal?: PortalConfig;
|
|
226
|
+
/** Org-scoped roles & permissions (builds on `organizations`). When present, mounts routes to
|
|
227
|
+
* list an org's role definitions and set a member's roles. Pair with
|
|
228
|
+
* `createMembershipPermissionResolver` to make `authorization.hasPermission` turnkey. */
|
|
229
|
+
roles?: RolesConfig<UserType>;
|
|
206
230
|
/** Role-based / attribute-based access control (E4). When present, `auth()` exposes a
|
|
207
231
|
* `protectPermission(check, handler)` derive (alongside `protectRoute`) that delegates the
|
|
208
232
|
* decision to your `hasPermission` hook — the package stays schema-agnostic about roles. */
|
|
@@ -217,6 +241,11 @@ export type AuthConfig<UserType> = {
|
|
|
217
241
|
* → mints the same `SessionData<UserType>`). A `webauthnAdapter` wraps a vetted library (e.g.
|
|
218
242
|
* `@simplewebauthn/server`); the package never bundles the WebAuthn crypto. */
|
|
219
243
|
webauthn?: WebAuthnConfig<UserType>;
|
|
244
|
+
/** Signed outbound webhooks. When present, every emitted auth event (the audit taxonomy) is
|
|
245
|
+
* HMAC-signed (Standard Webhooks scheme) and POSTed to each endpoint. Delivery is best-effort
|
|
246
|
+
* and isolated per endpoint; configuring this alone (without `audit`) is enough to turn on
|
|
247
|
+
* event emission. PII redaction (`audit.redact`) applies before delivery. */
|
|
248
|
+
webhooks?: WebhooksConfig;
|
|
220
249
|
/** Enable the built-in HTMX fragment routes (login, identities, connectors,
|
|
221
250
|
* account, signout, delete-account). Supply provider display data + the
|
|
222
251
|
* identity/connector data actions; the package owns the route wiring and
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { WebhookEndpoint, WebhookEvent } from './types';
|
|
2
|
+
export declare const DEFAULT_WEBHOOK_TIMEOUT_MS: number;
|
|
3
|
+
export type WebhookFetch = (url: string, init: {
|
|
4
|
+
body: string;
|
|
5
|
+
headers: Record<string, string>;
|
|
6
|
+
method: string;
|
|
7
|
+
signal: AbortSignal;
|
|
8
|
+
}) => Promise<{
|
|
9
|
+
ok: boolean;
|
|
10
|
+
status: number;
|
|
11
|
+
}>;
|
|
12
|
+
export type WebhooksConfig = {
|
|
13
|
+
endpoints: WebhookEndpoint[];
|
|
14
|
+
fetch?: WebhookFetch;
|
|
15
|
+
onDeliveryError?: (context: {
|
|
16
|
+
endpoint: WebhookEndpoint;
|
|
17
|
+
error: unknown;
|
|
18
|
+
event: WebhookEvent;
|
|
19
|
+
}) => void | Promise<void>;
|
|
20
|
+
timeoutMs?: number;
|
|
21
|
+
};
|