@adonis-agora/authkit-server 0.41.0 → 0.43.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.
|
@@ -561,6 +561,21 @@ export interface AuthServerConfigInput {
|
|
|
561
561
|
ttl?: TtlConfig;
|
|
562
562
|
/** Nome da CLAIM (não do scope) onde os papéis globais são emitidos. Default: 'roles'. */
|
|
563
563
|
globalRolesClaim?: string;
|
|
564
|
+
/**
|
|
565
|
+
* Resolves the global-roles claim at token-mint time. Return the roles to embed
|
|
566
|
+
* in the `<globalRolesClaim>` claim for a first-party client. Lets the host source
|
|
567
|
+
* roles from an external authority (e.g. @adonis-agora/authz) or a custom store
|
|
568
|
+
* instead of the account's stored `globalRoles`. Default when omitted:
|
|
569
|
+
* `account.globalRoles ?? []` (unchanged behavior).
|
|
570
|
+
*/
|
|
571
|
+
resolveTokenRoles?: (account: AuthAccount, context: {
|
|
572
|
+
clientId?: string;
|
|
573
|
+
activeOrg?: {
|
|
574
|
+
orgId: string;
|
|
575
|
+
orgSlug: string;
|
|
576
|
+
orgRole: string;
|
|
577
|
+
} | null;
|
|
578
|
+
}) => string[] | Promise<string[]>;
|
|
564
579
|
cookieKeys?: string[];
|
|
565
580
|
observability?: ObservabilityConfig;
|
|
566
581
|
/** Contrato primário de identidade. Deriva findAccount/verifyCredentials do provider. */
|
|
@@ -769,6 +784,18 @@ export interface ResolvedServerConfig {
|
|
|
769
784
|
session: number;
|
|
770
785
|
};
|
|
771
786
|
globalRolesClaim: string;
|
|
787
|
+
/**
|
|
788
|
+
* Resolves the global-roles claim at token-mint time (first-party only). When
|
|
789
|
+
* omitted, the mint falls back to `account.globalRoles ?? []` (unchanged behavior).
|
|
790
|
+
*/
|
|
791
|
+
resolveTokenRoles?: (account: AuthAccount, context: {
|
|
792
|
+
clientId?: string;
|
|
793
|
+
activeOrg?: {
|
|
794
|
+
orgId: string;
|
|
795
|
+
orgSlug: string;
|
|
796
|
+
orgRole: string;
|
|
797
|
+
} | null;
|
|
798
|
+
}) => string[] | Promise<string[]>;
|
|
772
799
|
cookieKeys: string[];
|
|
773
800
|
observability: ObservabilityConfig;
|
|
774
801
|
findAccount: (sub: string) => Promise<AuthAccount | null>;
|
|
@@ -303,6 +303,7 @@ export function defineConfig(config) {
|
|
|
303
303
|
session: toSeconds(config.ttl?.session, 604800),
|
|
304
304
|
},
|
|
305
305
|
globalRolesClaim: config.globalRolesClaim ?? "roles",
|
|
306
|
+
resolveTokenRoles: config.resolveTokenRoles,
|
|
306
307
|
cookieKeys: config.cookieKeys ?? [],
|
|
307
308
|
observability: config.observability ?? {},
|
|
308
309
|
findAccount: (sub) => config.accountStore.findById(sub),
|
|
@@ -98,7 +98,9 @@ export class OidcService {
|
|
|
98
98
|
};
|
|
99
99
|
// roles/org_* são dados de autorização interna: só para first-party.
|
|
100
100
|
if (firstParty) {
|
|
101
|
-
base[config.globalRolesClaim] =
|
|
101
|
+
base[config.globalRolesClaim] = config.resolveTokenRoles
|
|
102
|
+
? await config.resolveTokenRoles(user, { clientId, activeOrg })
|
|
103
|
+
: (user.globalRoles ?? []);
|
|
102
104
|
// Emite claims de org somente quando há uma org ativa na sessão.
|
|
103
105
|
if (activeOrg) {
|
|
104
106
|
base['org_id'] = activeOrg.orgId;
|
|
@@ -115,6 +117,7 @@ export class OidcService {
|
|
|
115
117
|
registerTokenExchange(provider, {
|
|
116
118
|
findAccount: config.findAccount,
|
|
117
119
|
globalRolesClaim: config.globalRolesClaim,
|
|
120
|
+
resolveTokenRoles: config.resolveTokenRoles,
|
|
118
121
|
// Resource indicators (RFC 8707) suportados: o `audience` default + cada
|
|
119
122
|
// resource declarado. Usado para validar `audience`/`resource` no pedido de
|
|
120
123
|
// token-exchange — alvos fora desta lista são rejeitados (invalid_target).
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AuditSink } from '../audit/audit_sink.js';
|
|
2
|
+
import type { AuthAccount } from '../accounts/account_store.js';
|
|
2
3
|
export interface TokenExchangeAccount {
|
|
3
4
|
id: string;
|
|
4
5
|
email?: string;
|
|
@@ -8,6 +9,20 @@ export interface TokenExchangeAccount {
|
|
|
8
9
|
export interface TokenExchangeDeps {
|
|
9
10
|
findAccount: (sub: string) => Promise<TokenExchangeAccount | null>;
|
|
10
11
|
globalRolesClaim: string;
|
|
12
|
+
/**
|
|
13
|
+
* Resolves the global-roles claim at token-mint time. When omitted, falls back to
|
|
14
|
+
* `target.globalRoles ?? []` (unchanged behavior). Mirrors the mint-time hook used
|
|
15
|
+
* by the authorization-code flow so impersonated tokens source roles from the same
|
|
16
|
+
* authority (e.g. @adonis-agora/authz) or custom store.
|
|
17
|
+
*/
|
|
18
|
+
resolveTokenRoles?: (account: AuthAccount, context: {
|
|
19
|
+
clientId?: string;
|
|
20
|
+
activeOrg?: {
|
|
21
|
+
orgId: string;
|
|
22
|
+
orgSlug: string;
|
|
23
|
+
orgRole: string;
|
|
24
|
+
} | null;
|
|
25
|
+
}) => string[] | Promise<string[]>;
|
|
11
26
|
adminRole?: string;
|
|
12
27
|
/**
|
|
13
28
|
* Resource indicators (RFC 8707) suportados pelo provider. Quando o pedido traz
|
|
@@ -82,12 +82,20 @@ export function registerTokenExchange(provider, deps) {
|
|
|
82
82
|
}
|
|
83
83
|
const at = new provider.AccessToken({ accountId: target.id, client, scope });
|
|
84
84
|
const accessToken = await at.save();
|
|
85
|
+
// Token exchange is not tied to a browser session, so there is no active org
|
|
86
|
+
// context here — roles are resolved for the impersonated target with clientId only.
|
|
87
|
+
const roles = deps.resolveTokenRoles
|
|
88
|
+
? await deps.resolveTokenRoles(target, {
|
|
89
|
+
clientId: client?.clientId,
|
|
90
|
+
activeOrg: null,
|
|
91
|
+
})
|
|
92
|
+
: (target.globalRoles ?? []);
|
|
85
93
|
const idToken = new provider.IdToken({
|
|
86
94
|
sub: target.id,
|
|
87
95
|
email: target.email,
|
|
88
96
|
email_verified: true,
|
|
89
97
|
name: target.name,
|
|
90
|
-
[deps.globalRolesClaim]:
|
|
98
|
+
[deps.globalRolesClaim]: roles,
|
|
91
99
|
}, { ctx });
|
|
92
100
|
idToken.scope = scope;
|
|
93
101
|
idToken.set('act', { sub: actor.id });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adonis-agora/authkit-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.43.0",
|
|
4
4
|
"description": "AdonisJS OIDC/OAuth2 provider (Identity Provider) toolkit: ejectable auth server with sessions, rate-limiting, MFA/TOTP, audit log, federated logout and OpenTelemetry metrics.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "dudousxd",
|
|
@@ -66,6 +66,7 @@
|
|
|
66
66
|
"@adonisjs/redis": "^9.2.0",
|
|
67
67
|
"@adonisjs/session": "^8.1.0",
|
|
68
68
|
"@adonisjs/shield": "^9.0.0",
|
|
69
|
+
"@vinejs/vine": "^4.3.0",
|
|
69
70
|
"edge.js": "^6.5.1"
|
|
70
71
|
},
|
|
71
72
|
"peerDependenciesMeta": {
|
|
@@ -96,7 +97,6 @@
|
|
|
96
97
|
},
|
|
97
98
|
"dependencies": {
|
|
98
99
|
"@simplewebauthn/server": "^13.3.1",
|
|
99
|
-
"@vinejs/vine": "4.4.0",
|
|
100
100
|
"jose": "^5.9.0",
|
|
101
101
|
"koa": "^3.2.1",
|
|
102
102
|
"koa-mount": "^4.2.0",
|
|
@@ -130,6 +130,7 @@
|
|
|
130
130
|
"ioredis-mock": "^8.9.0",
|
|
131
131
|
"luxon": "3.7.2",
|
|
132
132
|
"tailwindcss": "^3.4.19",
|
|
133
|
+
"@vinejs/vine": "4.4.0",
|
|
133
134
|
"typescript": "6.0.3",
|
|
134
135
|
"@vitejs/plugin-react": "6.0.2",
|
|
135
136
|
"@types/react": "19.2.15",
|