@adonis-agora/authkit-server 1.0.0-rc.2 → 1.0.0-rc.4
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 +19 -0
- package/build/commands/clients_create.d.ts +4 -0
- package/build/commands/clients_create.js +97 -0
- package/build/commands/commands.json +14 -0
- package/build/index.d.ts +3 -0
- package/build/index.js +1 -0
- package/build/src/audit/audit_sink.d.ts +1 -1
- package/build/src/audit/audit_sink.js +5 -0
- package/build/src/define_config.d.ts +16 -0
- package/build/src/define_config.js +2 -0
- package/build/src/host/access_token_verifier.js +7 -0
- package/build/src/host/admin_api/api_clients_controller.d.ts +37 -0
- package/build/src/host/admin_api/api_clients_controller.js +31 -1
- package/build/src/host/admin_api/dto.d.ts +3 -1
- package/build/src/host/admin_api/dto.js +2 -0
- package/build/src/host/admin_clients_service.d.ts +20 -0
- package/build/src/host/admin_clients_service.js +55 -0
- package/build/src/host/admin_console/console_clients_controller.d.ts +41 -0
- package/build/src/host/admin_console/console_clients_controller.js +34 -1
- package/build/src/host/admin_validators.d.ts +29 -0
- package/build/src/host/admin_validators.js +30 -0
- package/build/src/host/register_auth_host.js +4 -0
- package/build/src/host/ui-dist/assets/index-u0bMxkLg.js +67 -0
- package/build/src/host/ui-dist/index.html +1 -1
- package/build/src/provider/build_provider.js +37 -6
- package/build/src/service_tenants/client_metadata.d.ts +39 -0
- package/build/src/service_tenants/client_metadata.js +80 -0
- package/build/src/service_tenants/config.d.ts +44 -0
- package/build/src/service_tenants/config.js +44 -0
- package/build/src/service_tenants/provider_hooks.d.ts +52 -0
- package/build/src/service_tenants/provider_hooks.js +124 -0
- package/build/src/service_tenants/tenant_verifier.d.ts +73 -0
- package/build/src/service_tenants/tenant_verifier.js +104 -0
- package/package.json +3 -3
- package/build/src/host/ui-dist/assets/index-BqyJYRVX.js +0 -67
|
@@ -9,8 +9,11 @@ import type { HttpContext } from '@adonisjs/core/http';
|
|
|
9
9
|
* PATCH {prefix}/api/clients/:id → atualizar metadata
|
|
10
10
|
* DELETE {prefix}/api/clients/:id → remover client
|
|
11
11
|
* POST {prefix}/api/clients/:id/regenerate-secret → gerar novo secret
|
|
12
|
+
* POST {prefix}/api/clients/:id/disable → stop issuing tokens to the client
|
|
13
|
+
* POST {prefix}/api/clients/:id/enable → issue tokens again
|
|
12
14
|
*/
|
|
13
15
|
export default class ConsoleClientsController {
|
|
16
|
+
#private;
|
|
14
17
|
/** GET {prefix}/api/clients */
|
|
15
18
|
index(ctx: HttpContext): Promise<{
|
|
16
19
|
data: {
|
|
@@ -25,6 +28,8 @@ export default class ConsoleClientsController {
|
|
|
25
28
|
backchannelLogoutSessionRequired: boolean;
|
|
26
29
|
clientName: string | null;
|
|
27
30
|
logoUri: string | null;
|
|
31
|
+
disabled: boolean;
|
|
32
|
+
serviceTenant: import("../../service_tenants/client_metadata.ts").ServiceTenantInfo | null;
|
|
28
33
|
}[];
|
|
29
34
|
canList: boolean;
|
|
30
35
|
}>;
|
|
@@ -41,6 +46,8 @@ export default class ConsoleClientsController {
|
|
|
41
46
|
backchannelLogoutSessionRequired: boolean;
|
|
42
47
|
clientName: string | null;
|
|
43
48
|
logoUri: string | null;
|
|
49
|
+
disabled: boolean;
|
|
50
|
+
serviceTenant: import("../../service_tenants/client_metadata.ts").ServiceTenantInfo | null;
|
|
44
51
|
}>;
|
|
45
52
|
/** POST {prefix}/api/clients */
|
|
46
53
|
store(ctx: HttpContext): Promise<void | {
|
|
@@ -60,12 +67,46 @@ export default class ConsoleClientsController {
|
|
|
60
67
|
backchannelLogoutSessionRequired: boolean;
|
|
61
68
|
clientName: string | null;
|
|
62
69
|
logoUri: string | null;
|
|
70
|
+
disabled: boolean;
|
|
71
|
+
serviceTenant: import("../../service_tenants/client_metadata.ts").ServiceTenantInfo | null;
|
|
63
72
|
}>;
|
|
64
73
|
/** DELETE {prefix}/api/clients/:id */
|
|
65
74
|
destroy(ctx: HttpContext): Promise<void | {
|
|
66
75
|
ok: boolean;
|
|
67
76
|
deleted: string;
|
|
68
77
|
}>;
|
|
78
|
+
/** POST {prefix}/api/clients/:id/disable */
|
|
79
|
+
disable(ctx: HttpContext): Promise<void | {
|
|
80
|
+
clientId: string;
|
|
81
|
+
confidential: boolean;
|
|
82
|
+
grantTypes: string[];
|
|
83
|
+
redirectUris: string[];
|
|
84
|
+
postLogoutRedirectUris: string[];
|
|
85
|
+
tokenEndpointAuthMethod: string;
|
|
86
|
+
applicationType: import("../client_metadata.js").ApplicationType;
|
|
87
|
+
backchannelLogoutUri: string | null;
|
|
88
|
+
backchannelLogoutSessionRequired: boolean;
|
|
89
|
+
clientName: string | null;
|
|
90
|
+
logoUri: string | null;
|
|
91
|
+
disabled: boolean;
|
|
92
|
+
serviceTenant: import("../../service_tenants/client_metadata.ts").ServiceTenantInfo | null;
|
|
93
|
+
}>;
|
|
94
|
+
/** POST {prefix}/api/clients/:id/enable */
|
|
95
|
+
enable(ctx: HttpContext): Promise<void | {
|
|
96
|
+
clientId: string;
|
|
97
|
+
confidential: boolean;
|
|
98
|
+
grantTypes: string[];
|
|
99
|
+
redirectUris: string[];
|
|
100
|
+
postLogoutRedirectUris: string[];
|
|
101
|
+
tokenEndpointAuthMethod: string;
|
|
102
|
+
applicationType: import("../client_metadata.js").ApplicationType;
|
|
103
|
+
backchannelLogoutUri: string | null;
|
|
104
|
+
backchannelLogoutSessionRequired: boolean;
|
|
105
|
+
clientName: string | null;
|
|
106
|
+
logoUri: string | null;
|
|
107
|
+
disabled: boolean;
|
|
108
|
+
serviceTenant: import("../../service_tenants/client_metadata.ts").ServiceTenantInfo | null;
|
|
109
|
+
}>;
|
|
69
110
|
/** POST {prefix}/api/clients/:id/regenerate-secret */
|
|
70
111
|
regenerateSecret(ctx: HttpContext): Promise<void | {
|
|
71
112
|
clientId: string;
|
|
@@ -19,6 +19,8 @@ function invalidMetadata(ctx, err) {
|
|
|
19
19
|
* PATCH {prefix}/api/clients/:id → atualizar metadata
|
|
20
20
|
* DELETE {prefix}/api/clients/:id → remover client
|
|
21
21
|
* POST {prefix}/api/clients/:id/regenerate-secret → gerar novo secret
|
|
22
|
+
* POST {prefix}/api/clients/:id/disable → stop issuing tokens to the client
|
|
23
|
+
* POST {prefix}/api/clients/:id/enable → issue tokens again
|
|
22
24
|
*/
|
|
23
25
|
export default class ConsoleClientsController {
|
|
24
26
|
/** GET {prefix}/api/clients */
|
|
@@ -107,6 +109,34 @@ export default class ConsoleClientsController {
|
|
|
107
109
|
});
|
|
108
110
|
return { ok: true, deleted: id };
|
|
109
111
|
}
|
|
112
|
+
/** POST {prefix}/api/clients/:id/disable */
|
|
113
|
+
async disable(ctx) {
|
|
114
|
+
return this.#setDisabled(ctx, true);
|
|
115
|
+
}
|
|
116
|
+
/** POST {prefix}/api/clients/:id/enable */
|
|
117
|
+
async enable(ctx) {
|
|
118
|
+
return this.#setDisabled(ctx, false);
|
|
119
|
+
}
|
|
120
|
+
/** Disabled clients get `invalid_client` from the next request on. */
|
|
121
|
+
async #setDisabled(ctx, disabled) {
|
|
122
|
+
const service = await ctx.containerResolver.make('authkit.server');
|
|
123
|
+
const svc = new AdminClientsService(service);
|
|
124
|
+
const id = ctx.request.param('id');
|
|
125
|
+
if (!(await svc.setDisabled(id, disabled))) {
|
|
126
|
+
return ctx.response.notFound(apiError('not_found', 'Client não encontrado.'));
|
|
127
|
+
}
|
|
128
|
+
const client = await svc.find(id);
|
|
129
|
+
await service.config.audit?.record({
|
|
130
|
+
type: disabled ? 'client.disabled' : 'client.enabled',
|
|
131
|
+
clientId: id,
|
|
132
|
+
ip: ctx.request.ip?.() ?? null,
|
|
133
|
+
metadata: {
|
|
134
|
+
actor: 'admin-console',
|
|
135
|
+
...(client?.serviceTenant ? { partition: client.serviceTenant.partition } : {}),
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
return clientDto(client);
|
|
139
|
+
}
|
|
110
140
|
/** POST {prefix}/api/clients/:id/regenerate-secret */
|
|
111
141
|
async regenerateSecret(ctx) {
|
|
112
142
|
const service = await ctx.containerResolver.make('authkit.server');
|
|
@@ -129,7 +159,10 @@ export default class ConsoleClientsController {
|
|
|
129
159
|
type: 'client.secret_regenerated',
|
|
130
160
|
clientId: id,
|
|
131
161
|
ip: ctx.request.ip?.() ?? null,
|
|
132
|
-
metadata: {
|
|
162
|
+
metadata: {
|
|
163
|
+
actor: 'admin-console',
|
|
164
|
+
...(existing.serviceTenant ? { partition: existing.serviceTenant.partition } : {}),
|
|
165
|
+
},
|
|
133
166
|
});
|
|
134
167
|
return { clientId: id, clientSecret: newSecret };
|
|
135
168
|
}
|
|
@@ -17,6 +17,19 @@ export declare const clientInputValidator: import("@vinejs/vine").VineValidator<
|
|
|
17
17
|
backchannelLogoutSessionRequired: import("@vinejs/vine/schema/base/literal").OptionalModifier<import("@vinejs/vine").VineBoolean>;
|
|
18
18
|
clientName: import("@vinejs/vine/schema/base/literal").OptionalModifier<import("@vinejs/vine/schema/base/literal").NullableModifier<import("@vinejs/vine").VineString>>;
|
|
19
19
|
logoUri: import("@vinejs/vine/schema/base/literal").OptionalModifier<import("@vinejs/vine/schema/base/literal").NullableModifier<import("@vinejs/vine").VineString>>;
|
|
20
|
+
serviceTenant: import("@vinejs/vine").OptionalModifier<import("@vinejs/vine").NullableModifier<import("@vinejs/vine").VineObject<{
|
|
21
|
+
partition: import("@vinejs/vine").VineString;
|
|
22
|
+
capabilities: import("@vinejs/vine").OptionalModifier<import("@vinejs/vine").VineArray<import("@vinejs/vine").VineString>>;
|
|
23
|
+
}, {
|
|
24
|
+
capabilities?: string[] | null | undefined;
|
|
25
|
+
partition: string;
|
|
26
|
+
}, {
|
|
27
|
+
capabilities?: string[] | undefined;
|
|
28
|
+
partition: string;
|
|
29
|
+
}, {
|
|
30
|
+
capabilities?: string[] | undefined;
|
|
31
|
+
partition: string;
|
|
32
|
+
}>>>;
|
|
20
33
|
}, {
|
|
21
34
|
applicationType?: "native" | "web" | null | undefined;
|
|
22
35
|
backchannelLogoutSessionRequired?: string | number | boolean | null | undefined;
|
|
@@ -27,6 +40,10 @@ export declare const clientInputValidator: import("@vinejs/vine").VineValidator<
|
|
|
27
40
|
logoUri?: string | null | undefined;
|
|
28
41
|
postLogoutRedirectUris?: string[] | null | undefined;
|
|
29
42
|
redirectUris?: string[] | null | undefined;
|
|
43
|
+
serviceTenant?: {
|
|
44
|
+
capabilities?: string[] | null | undefined;
|
|
45
|
+
partition: string;
|
|
46
|
+
} | null | undefined;
|
|
30
47
|
tokenEndpointAuthMethod?: "client_secret_basic" | "client_secret_post" | "none" | null | undefined;
|
|
31
48
|
}, {
|
|
32
49
|
applicationType?: "native" | "web" | undefined;
|
|
@@ -38,6 +55,10 @@ export declare const clientInputValidator: import("@vinejs/vine").VineValidator<
|
|
|
38
55
|
logoUri?: string | null | undefined;
|
|
39
56
|
postLogoutRedirectUris?: string[] | undefined;
|
|
40
57
|
redirectUris?: string[] | undefined;
|
|
58
|
+
serviceTenant?: {
|
|
59
|
+
capabilities?: string[] | undefined;
|
|
60
|
+
partition: string;
|
|
61
|
+
} | null | undefined;
|
|
41
62
|
tokenEndpointAuthMethod?: "client_secret_basic" | "client_secret_post" | "none" | undefined;
|
|
42
63
|
}, {
|
|
43
64
|
applicationType?: "native" | "web" | undefined;
|
|
@@ -49,6 +70,10 @@ export declare const clientInputValidator: import("@vinejs/vine").VineValidator<
|
|
|
49
70
|
logoUri?: string | null | undefined;
|
|
50
71
|
postLogoutRedirectUris?: string[] | undefined;
|
|
51
72
|
redirectUris?: string[] | undefined;
|
|
73
|
+
serviceTenant?: {
|
|
74
|
+
capabilities?: string[] | undefined;
|
|
75
|
+
partition: string;
|
|
76
|
+
} | null | undefined;
|
|
52
77
|
tokenEndpointAuthMethod?: "client_secret_basic" | "client_secret_post" | "none" | undefined;
|
|
53
78
|
}>, Record<string, any> | undefined>;
|
|
54
79
|
/** Forma validada de um client (saída do {@link clientInputValidator}). */
|
|
@@ -63,6 +88,10 @@ export type ClientInputFields = {
|
|
|
63
88
|
backchannelLogoutSessionRequired?: boolean;
|
|
64
89
|
clientName?: string | null;
|
|
65
90
|
logoUri?: string | null;
|
|
91
|
+
serviceTenant?: {
|
|
92
|
+
partition: string;
|
|
93
|
+
capabilities?: string[];
|
|
94
|
+
} | null;
|
|
66
95
|
};
|
|
67
96
|
/**
|
|
68
97
|
* Mapeia o input validado para um {@link ClientInput} COMPLETO (create), com defaults.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import vine from '@vinejs/vine';
|
|
2
|
+
import { CAPABILITY_PATTERN, MAX_CAPABILITIES, PARTITION_PATTERN, } from '../service_tenants/client_metadata.js';
|
|
2
3
|
import { APPLICATION_TYPES, redirectUriProblem } from './client_metadata.js';
|
|
3
4
|
import { normalizeEmailIdentifier } from './email_identifier.js';
|
|
4
5
|
/**
|
|
@@ -103,6 +104,18 @@ export const clientInputValidator = vine.compile(vine.object({
|
|
|
103
104
|
// `null` (update) removes them.
|
|
104
105
|
clientName: vine.string().trim().maxLength(200).nullable().optional(),
|
|
105
106
|
logoUri: vine.string().trim().url(URL_OPTS).nullable().optional(),
|
|
107
|
+
// Service tenant (`client_credentials` + partition claim). `null` (update) turns it
|
|
108
|
+
// back into a regular client.
|
|
109
|
+
serviceTenant: vine
|
|
110
|
+
.object({
|
|
111
|
+
partition: vine.string().trim().regex(PARTITION_PATTERN),
|
|
112
|
+
capabilities: vine
|
|
113
|
+
.array(vine.string().trim().regex(CAPABILITY_PATTERN))
|
|
114
|
+
.maxLength(MAX_CAPABILITIES)
|
|
115
|
+
.optional(),
|
|
116
|
+
})
|
|
117
|
+
.nullable()
|
|
118
|
+
.optional(),
|
|
106
119
|
}));
|
|
107
120
|
/**
|
|
108
121
|
* Mapeia o input validado para um {@link ClientInput} COMPLETO (create), com defaults.
|
|
@@ -111,6 +124,21 @@ export const clientInputValidator = vine.compile(vine.object({
|
|
|
111
124
|
*/
|
|
112
125
|
export function clientCreateInput(v) {
|
|
113
126
|
const applicationType = v.applicationType ?? 'web';
|
|
127
|
+
// A service tenant only uses client_credentials: that is its default grant.
|
|
128
|
+
if (v.serviceTenant) {
|
|
129
|
+
return {
|
|
130
|
+
clientId: v.clientId?.trim() || undefined,
|
|
131
|
+
applicationType,
|
|
132
|
+
redirectUris: v.redirectUris ?? [],
|
|
133
|
+
postLogoutRedirectUris: v.postLogoutRedirectUris ?? [],
|
|
134
|
+
grantTypes: v.grantTypes ?? ['client_credentials'],
|
|
135
|
+
tokenEndpointAuthMethod: v.tokenEndpointAuthMethod ?? 'client_secret_basic',
|
|
136
|
+
backchannelLogoutUri: v.backchannelLogoutUri || undefined,
|
|
137
|
+
clientName: v.clientName || undefined,
|
|
138
|
+
logoUri: v.logoUri || undefined,
|
|
139
|
+
serviceTenant: v.serviceTenant,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
114
142
|
return {
|
|
115
143
|
clientId: v.clientId?.trim() || undefined,
|
|
116
144
|
applicationType,
|
|
@@ -148,6 +176,8 @@ export function clientPartialInput(v) {
|
|
|
148
176
|
out.clientName = v.clientName?.trim() || null;
|
|
149
177
|
if (v.logoUri !== undefined)
|
|
150
178
|
out.logoUri = v.logoUri?.trim() || null;
|
|
179
|
+
if (v.serviceTenant !== undefined)
|
|
180
|
+
out.serviceTenant = v.serviceTenant;
|
|
151
181
|
return out;
|
|
152
182
|
}
|
|
153
183
|
// ─── Usuários ───────────────────────────────────────────────────────────────
|
|
@@ -997,6 +997,8 @@ export function registerAuthHost(router, opts = {}) {
|
|
|
997
997
|
router.get(`${ap}/api/clients/:id`, [C.consoleClients, 'show']);
|
|
998
998
|
router.patch(`${ap}/api/clients/:id`, [C.consoleClients, 'update']);
|
|
999
999
|
router.delete(`${ap}/api/clients/:id`, [C.consoleClients, 'destroy']);
|
|
1000
|
+
router.post(`${ap}/api/clients/:id/disable`, [C.consoleClients, 'disable']);
|
|
1001
|
+
router.post(`${ap}/api/clients/:id/enable`, [C.consoleClients, 'enable']);
|
|
1000
1002
|
router.post(`${ap}/api/clients/:id/regenerate-secret`, [
|
|
1001
1003
|
C.consoleClients,
|
|
1002
1004
|
'regenerateSecret',
|
|
@@ -1096,6 +1098,8 @@ export function registerAuthHost(router, opts = {}) {
|
|
|
1096
1098
|
withApiThrottle(router.patch('/clients/:id', [C.apiClients, 'update']));
|
|
1097
1099
|
withApiThrottle(router.post('/clients/:id/regenerate-secret', [C.apiClients, 'regenerateSecret']));
|
|
1098
1100
|
withApiThrottle(router.delete('/clients/:id', [C.apiClients, 'destroy']));
|
|
1101
|
+
withApiThrottle(router.post('/clients/:id/disable', [C.apiClients, 'disable']));
|
|
1102
|
+
withApiThrottle(router.post('/clients/:id/enable', [C.apiClients, 'enable']));
|
|
1099
1103
|
// Organizações.
|
|
1100
1104
|
withApiThrottle(router.get('/organizations', [C.apiOrgs, 'index']));
|
|
1101
1105
|
withApiThrottle(router.post('/organizations', [C.apiOrgs, 'store']));
|