@adonis-agora/authkit-core 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/LICENSE +21 -0
- package/README.md +25 -0
- package/build/index.d.ts +6 -0
- package/build/index.js +2 -0
- package/build/src/metrics.d.ts +15 -0
- package/build/src/metrics.js +14 -0
- package/build/src/metrics_recorder.d.ts +33 -0
- package/build/src/metrics_recorder.js +32 -0
- package/build/src/types/identity.d.ts +32 -0
- package/build/src/types/identity.js +1 -0
- package/build/src/types/server_config.d.ts +145 -0
- package/build/src/types/server_config.js +1 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Davi de Carvalho
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# @adonis-agora/authkit-core
|
|
2
|
+
|
|
3
|
+
Contratos compartilhados do AuthKit: `Identity`, `SessionResolver`, tipos de config
|
|
4
|
+
do server e nomes de métricas. Sem runtime — consumido por `@adonis-agora/authkit-server` e `@adonis-agora/authkit-client`.
|
|
5
|
+
|
|
6
|
+
Normalmente você não instala este pacote diretamente: ele vem como dependência
|
|
7
|
+
do server e do client. Mas, se precisar dos tipos compartilhados:
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @adonis-agora/authkit-core
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import type { Identity, SessionResolver } from '@adonis-agora/authkit-core'
|
|
19
|
+
|
|
20
|
+
const resolver: SessionResolver = {
|
|
21
|
+
async resolve(): Promise<Identity | null> {
|
|
22
|
+
return null
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
```
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { Identity, SessionResolver } from './src/types/identity.js';
|
|
2
|
+
export type { ClientConfig, TtlConfig, JwksConfig, KeystoreStoreConfig, ObservabilityConfig, ResolvedAuthServerConfig, AccessTokenFormat, AccessTokenResourceConfig, AccessTokensConfig, } from './src/types/server_config.js';
|
|
3
|
+
export { AUTHKIT_METRICS } from './src/metrics.js';
|
|
4
|
+
export type { AuthkitMetricName } from './src/metrics.js';
|
|
5
|
+
export { InMemorySnapshot, NoopRecorder } from './src/metrics_recorder.js';
|
|
6
|
+
export type { MetricsRecorder, MetricsSnapshot } from './src/metrics_recorder.js';
|
package/build/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Nomes canônicos das métricas OTel emitidas pela lib (usados no Plano 3). */
|
|
2
|
+
export declare const AUTHKIT_METRICS: {
|
|
3
|
+
readonly loginSuccess: "authkit.login.success";
|
|
4
|
+
readonly loginFailure: "authkit.login.failure";
|
|
5
|
+
readonly tokenIssued: "authkit.token.issued";
|
|
6
|
+
readonly refreshRotated: "authkit.refresh.rotated";
|
|
7
|
+
readonly grantRevoked: "authkit.grant.revoked";
|
|
8
|
+
readonly sessionsActive: "authkit.sessions.active";
|
|
9
|
+
readonly passwordHashDuration: "authkit.password.hash.duration";
|
|
10
|
+
readonly resolveDuration: "authkit.resolve.duration";
|
|
11
|
+
readonly resolveErrors: "authkit.resolve.errors";
|
|
12
|
+
readonly jwksRefresh: "authkit.jwks.refresh";
|
|
13
|
+
readonly tokenRefresh: "authkit.token.refresh";
|
|
14
|
+
};
|
|
15
|
+
export type AuthkitMetricName = (typeof AUTHKIT_METRICS)[keyof typeof AUTHKIT_METRICS];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Nomes canônicos das métricas OTel emitidas pela lib (usados no Plano 3). */
|
|
2
|
+
export const AUTHKIT_METRICS = {
|
|
3
|
+
loginSuccess: 'authkit.login.success',
|
|
4
|
+
loginFailure: 'authkit.login.failure',
|
|
5
|
+
tokenIssued: 'authkit.token.issued',
|
|
6
|
+
refreshRotated: 'authkit.refresh.rotated',
|
|
7
|
+
grantRevoked: 'authkit.grant.revoked',
|
|
8
|
+
sessionsActive: 'authkit.sessions.active',
|
|
9
|
+
passwordHashDuration: 'authkit.password.hash.duration',
|
|
10
|
+
resolveDuration: 'authkit.resolve.duration',
|
|
11
|
+
resolveErrors: 'authkit.resolve.errors',
|
|
12
|
+
jwksRefresh: 'authkit.jwks.refresh',
|
|
13
|
+
tokenRefresh: 'authkit.token.refresh',
|
|
14
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { AUTHKIT_METRICS, type AuthkitMetricName } from './metrics.js';
|
|
2
|
+
/** Recorder de métricas: counters e histograms nomeados. */
|
|
3
|
+
export interface MetricsRecorder {
|
|
4
|
+
increment(name: AuthkitMetricName, attributes?: Record<string, string | number>): void;
|
|
5
|
+
record(name: AuthkitMetricName, value: number, attributes?: Record<string, string | number>): void;
|
|
6
|
+
/** snapshot agregado em memória (para rota JSON / dashboard) */
|
|
7
|
+
snapshot(): MetricsSnapshot;
|
|
8
|
+
}
|
|
9
|
+
export interface MetricsSnapshot {
|
|
10
|
+
counters: Record<string, number>;
|
|
11
|
+
histograms: Record<string, {
|
|
12
|
+
count: number;
|
|
13
|
+
sum: number;
|
|
14
|
+
min: number;
|
|
15
|
+
max: number;
|
|
16
|
+
}>;
|
|
17
|
+
updatedAt: number;
|
|
18
|
+
}
|
|
19
|
+
/** Agregador em memória reaproveitável por qualquer recorder. */
|
|
20
|
+
export declare class InMemorySnapshot {
|
|
21
|
+
#private;
|
|
22
|
+
bump(name: string, by?: number): void;
|
|
23
|
+
observe(name: string, value: number): void;
|
|
24
|
+
read(): MetricsSnapshot;
|
|
25
|
+
}
|
|
26
|
+
/** No-op: usado quando observability está desligada. */
|
|
27
|
+
export declare class NoopRecorder implements MetricsRecorder {
|
|
28
|
+
increment(): void;
|
|
29
|
+
record(): void;
|
|
30
|
+
snapshot(): MetricsSnapshot;
|
|
31
|
+
}
|
|
32
|
+
export { AUTHKIT_METRICS };
|
|
33
|
+
export type { AuthkitMetricName };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { AUTHKIT_METRICS } from './metrics.js';
|
|
2
|
+
/** Agregador em memória reaproveitável por qualquer recorder. */
|
|
3
|
+
export class InMemorySnapshot {
|
|
4
|
+
#counters = {};
|
|
5
|
+
#histograms = {};
|
|
6
|
+
#updatedAt = 0;
|
|
7
|
+
bump(name, by = 1) {
|
|
8
|
+
this.#counters[name] = (this.#counters[name] ?? 0) + by;
|
|
9
|
+
this.#updatedAt = Date.now();
|
|
10
|
+
}
|
|
11
|
+
observe(name, value) {
|
|
12
|
+
const h = this.#histograms[name] ?? { count: 0, sum: 0, min: value, max: value };
|
|
13
|
+
h.count += 1;
|
|
14
|
+
h.sum += value;
|
|
15
|
+
h.min = Math.min(h.min, value);
|
|
16
|
+
h.max = Math.max(h.max, value);
|
|
17
|
+
this.#histograms[name] = h;
|
|
18
|
+
this.#updatedAt = Date.now();
|
|
19
|
+
}
|
|
20
|
+
read() {
|
|
21
|
+
return { counters: { ...this.#counters }, histograms: { ...this.#histograms }, updatedAt: this.#updatedAt };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** No-op: usado quando observability está desligada. */
|
|
25
|
+
export class NoopRecorder {
|
|
26
|
+
increment() { }
|
|
27
|
+
record() { }
|
|
28
|
+
snapshot() {
|
|
29
|
+
return { counters: {}, histograms: {}, updatedAt: 0 };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export { AUTHKIT_METRICS };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
2
|
+
/**
|
|
3
|
+
* Identidade resolvida por request a partir das claims OIDC validadas.
|
|
4
|
+
* Fronteira: só identidade (claims globais) — nada de domínio do app.
|
|
5
|
+
*/
|
|
6
|
+
export interface Identity {
|
|
7
|
+
/** claim `sub` */
|
|
8
|
+
userId: string;
|
|
9
|
+
email: string;
|
|
10
|
+
/** papéis globais, de uma claim custom (ex.: `roles`) */
|
|
11
|
+
globalRoles: string[];
|
|
12
|
+
/** claims OIDC padrão de perfil */
|
|
13
|
+
profile?: {
|
|
14
|
+
name?: string;
|
|
15
|
+
avatarUrl?: string;
|
|
16
|
+
};
|
|
17
|
+
/** `sid` quando presente */
|
|
18
|
+
sessionId?: string;
|
|
19
|
+
/** `iat` em epoch ms */
|
|
20
|
+
issuedAt: number;
|
|
21
|
+
/** `exp` em epoch ms */
|
|
22
|
+
expiresAt: number;
|
|
23
|
+
/** claims completas (escape hatch) */
|
|
24
|
+
raw: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Contrato do driver de resolução de sessão (estratégia por request).
|
|
28
|
+
* v1 do client implementa `resolvers.jwt()`.
|
|
29
|
+
*/
|
|
30
|
+
export interface SessionResolver {
|
|
31
|
+
resolve(ctx: HttpContext): Promise<Identity | null>;
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client OIDC persistido no adapter/DB, gerenciável via console admin ou Admin API
|
|
3
|
+
* em runtime. Usado internamente pela lib para representar clients em memória.
|
|
4
|
+
*/
|
|
5
|
+
export interface ClientConfig {
|
|
6
|
+
clientId: string;
|
|
7
|
+
clientSecret?: string;
|
|
8
|
+
redirectUris: string[];
|
|
9
|
+
postLogoutRedirectUris?: string[];
|
|
10
|
+
grants?: string[];
|
|
11
|
+
/** 'none' para public clients (SPA com PKCE) */
|
|
12
|
+
tokenEndpointAuthMethod?: 'client_secret_basic' | 'client_secret_post' | 'none';
|
|
13
|
+
/**
|
|
14
|
+
* Endpoint do RP que recebe o POST de OIDC Back-Channel Logout. Quando definido,
|
|
15
|
+
* o IdP envia um `logout_token` para esta URI ao encerrar a sessão/grant do usuário.
|
|
16
|
+
*/
|
|
17
|
+
backchannelLogoutUri?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Exige que o `logout_token` inclua a claim `sid` (session id). Mapeado para
|
|
20
|
+
* `backchannel_logout_session_required` do oidc-provider. Default: false.
|
|
21
|
+
*/
|
|
22
|
+
backchannelLogoutSessionRequired?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface TtlConfig {
|
|
25
|
+
accessToken?: string | number;
|
|
26
|
+
refreshToken?: string | number;
|
|
27
|
+
idToken?: string | number;
|
|
28
|
+
session?: string | number;
|
|
29
|
+
}
|
|
30
|
+
/** Config de onde o keystore managed mora. String = atalho p/ { driver:'file', path }. */
|
|
31
|
+
export type KeystoreStoreConfig = string | {
|
|
32
|
+
driver: 'file';
|
|
33
|
+
path: string;
|
|
34
|
+
} | {
|
|
35
|
+
driver: 'drive';
|
|
36
|
+
disk?: string;
|
|
37
|
+
key: string;
|
|
38
|
+
} | {
|
|
39
|
+
driver: 'lucid';
|
|
40
|
+
table?: string;
|
|
41
|
+
connection?: string;
|
|
42
|
+
key?: string;
|
|
43
|
+
} | {
|
|
44
|
+
driver: 'redis';
|
|
45
|
+
connection?: string;
|
|
46
|
+
key?: string;
|
|
47
|
+
} | {
|
|
48
|
+
driver: 'hashicorp-vault';
|
|
49
|
+
endpoint: string;
|
|
50
|
+
path: string;
|
|
51
|
+
token?: string;
|
|
52
|
+
mount?: string;
|
|
53
|
+
field?: string;
|
|
54
|
+
} | {
|
|
55
|
+
driver: 'aws-secrets-manager';
|
|
56
|
+
secretId: string;
|
|
57
|
+
region?: string;
|
|
58
|
+
} | {
|
|
59
|
+
driver: 'gcp-secret-manager';
|
|
60
|
+
name: string;
|
|
61
|
+
} | {
|
|
62
|
+
driver: 'azure-key-vault';
|
|
63
|
+
vaultUrl: string;
|
|
64
|
+
secretName: string;
|
|
65
|
+
};
|
|
66
|
+
export interface JwksConfig {
|
|
67
|
+
/** 'managed' = lib gera/rotaciona/persiste; 'jwks' = fornecido inline */
|
|
68
|
+
source: 'managed' | 'jwks';
|
|
69
|
+
/** usado quando source='managed' */
|
|
70
|
+
rotationDays?: number;
|
|
71
|
+
algorithm?: 'RS256' | 'ES256' | 'PS256' | 'EdDSA';
|
|
72
|
+
/**
|
|
73
|
+
* Onde o keystore PRIVADO managed é persistido. String = atalho p/ arquivo
|
|
74
|
+
* (`{driver:'file', path}`). Objeto `{ driver }` = cofre (file/drive/vault).
|
|
75
|
+
* Ausente = chave efêmera por boot (sem rotação real).
|
|
76
|
+
*/
|
|
77
|
+
store?: KeystoreStoreConfig;
|
|
78
|
+
/** Encripta o keystore em repouso (APP_KEY). Default backend-aware: file/drive ON, vault real OFF. */
|
|
79
|
+
encrypt?: boolean;
|
|
80
|
+
/** usado quando source='jwks' */
|
|
81
|
+
keys?: Record<string, unknown>[];
|
|
82
|
+
}
|
|
83
|
+
export interface ObservabilityConfig {
|
|
84
|
+
metrics?: boolean;
|
|
85
|
+
jsonRoutes?: boolean;
|
|
86
|
+
dashboard?: boolean;
|
|
87
|
+
}
|
|
88
|
+
/** Formato de emissão de um Access Token. */
|
|
89
|
+
export type AccessTokenFormat = 'opaque' | 'jwt';
|
|
90
|
+
/**
|
|
91
|
+
* Configuração de um Resource Server (API) endereçável por um resource indicator
|
|
92
|
+
* (RFC 8707). O resource indicator é a CHAVE no mapa `resources` — uma URI que
|
|
93
|
+
* identifica a API (ex.: 'https://api.acme.com'). Quando o client solicita esse
|
|
94
|
+
* `resource` no authorize/token, o Access Token emitido herda estas opções.
|
|
95
|
+
*/
|
|
96
|
+
export interface AccessTokenResourceConfig {
|
|
97
|
+
/**
|
|
98
|
+
* Valor da claim `aud` do JWT AT. Default: o próprio resource indicator (a chave).
|
|
99
|
+
*/
|
|
100
|
+
audience?: string;
|
|
101
|
+
/**
|
|
102
|
+
* Scopes que ESTA API aceita (space/array). Quando omitido, todos os scopes do
|
|
103
|
+
* provider são oferecidos a esta resource.
|
|
104
|
+
*/
|
|
105
|
+
scopes?: string[];
|
|
106
|
+
/** Formato do AT para esta resource. Default: herda o `accessTokens.format`. */
|
|
107
|
+
format?: AccessTokenFormat;
|
|
108
|
+
/** TTL do AT (segundos) para esta resource. Default: herda `ttl.accessToken`. */
|
|
109
|
+
expiresIn?: number;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Access Tokens (RFC 9068 — JWT Profile for OAuth 2.0 Access Tokens).
|
|
113
|
+
*
|
|
114
|
+
* - `format: 'opaque'` (DEFAULT): o AT é uma string opaca introspecionável (comportamento atual).
|
|
115
|
+
* - `format: 'jwt'`: TODO AT vira um JWT RFC 9068 (`typ: at+jwt`, claims
|
|
116
|
+
* iss/sub/aud/exp/iat/jti/client_id/scope), assinado com a chave do JWKS e
|
|
117
|
+
* validável só com o discovery/jwks_uri.
|
|
118
|
+
*
|
|
119
|
+
* O `audience` (modo simples jwt) define a claim `aud` do token; default = issuer.
|
|
120
|
+
*
|
|
121
|
+
* `resources` mapeia resource indicators (RFC 8707) → configuração por API: cada
|
|
122
|
+
* chave é a URI da API que o client solicita via `resource`, permitindo audiences,
|
|
123
|
+
* scopes, formato e TTL distintos por API. O caso simples NÃO precisa de `resources`.
|
|
124
|
+
*/
|
|
125
|
+
export interface AccessTokensConfig {
|
|
126
|
+
/** Formato default de TODOS os ATs sem resource explícito. Default: 'opaque'. */
|
|
127
|
+
format?: AccessTokenFormat;
|
|
128
|
+
/**
|
|
129
|
+
* Claim `aud` do JWT AT no modo simples (sem `resources`). Também é o resource
|
|
130
|
+
* indicator default usado quando `format: 'jwt'`. Default: o issuer.
|
|
131
|
+
*/
|
|
132
|
+
audience?: string;
|
|
133
|
+
/** Resource Servers (APIs) endereçáveis por resource indicator (RFC 8707). */
|
|
134
|
+
resources?: Record<string, AccessTokenResourceConfig>;
|
|
135
|
+
}
|
|
136
|
+
/** Forma normalizada do config do server (pós-`defineConfig`). */
|
|
137
|
+
export interface ResolvedAuthServerConfig {
|
|
138
|
+
issuer: string;
|
|
139
|
+
clients: ClientConfig[];
|
|
140
|
+
ttl: Required<TtlConfig>;
|
|
141
|
+
jwks: JwksConfig;
|
|
142
|
+
globalRolesClaim: string;
|
|
143
|
+
cookieKeys: string[];
|
|
144
|
+
observability: ObservabilityConfig;
|
|
145
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@adonis-agora/authkit-core",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "Shared core types and utilities for AuthKit — the AdonisJS OIDC/OAuth2 server and client toolkits.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "dudousxd",
|
|
7
|
+
"homepage": "https://github.com/DavideCarvalho/adonis-authkit/tree/main/packages/authkit-core#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/DavideCarvalho/adonis-authkit.git",
|
|
11
|
+
"directory": "packages/authkit-core"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/DavideCarvalho/adonis-authkit/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"adonisjs",
|
|
18
|
+
"oidc",
|
|
19
|
+
"oauth2",
|
|
20
|
+
"openid-connect",
|
|
21
|
+
"authentication",
|
|
22
|
+
"authkit"
|
|
23
|
+
],
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"type": "module",
|
|
28
|
+
"main": "./build/index.js",
|
|
29
|
+
"types": "./build/index.d.ts",
|
|
30
|
+
"files": [
|
|
31
|
+
"build"
|
|
32
|
+
],
|
|
33
|
+
"exports": {
|
|
34
|
+
".": "./build/index.js",
|
|
35
|
+
"./types": "./build/index.js"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@adonisjs/core": "7.3.3",
|
|
39
|
+
"@adonisjs/tsconfig": "2.0.0",
|
|
40
|
+
"@types/node": "25.9.1",
|
|
41
|
+
"typescript": "6.0.3"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsc",
|
|
45
|
+
"typecheck": "tsc --noEmit"
|
|
46
|
+
}
|
|
47
|
+
}
|