agntcy-dir 1.0.0 → 1.2.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/README.md CHANGED
@@ -105,6 +105,43 @@ const jwtTransport = await Client.createGRPCTransport(jwtConfig);
105
105
  const jwtClient = new Client(jwtConfig, jwtTransport);
106
106
  ```
107
107
 
108
+ ### OAuth 2.0 for Directory bearer auth
109
+
110
+ The SDK supports OIDC/OAuth for Directory bearer authentication on gRPC:
111
+
112
+ - Interactive login via Authorization Code + PKCE with a loopback callback (`authenticateOAuthPkce()`)
113
+ - Pre-issued access token via `DIRECTORY_CLIENT_AUTH_TOKEN`
114
+
115
+ Interactive PKCE sessions are cached alongside other Directory tooling at `$XDG_CONFIG_HOME/dirctl/auth-token.json` or `~/.config/dirctl/auth-token.json`. Pre-issued tokens from configuration are used directly and are not written to the cache by the constructor.
116
+
117
+ Use this mode when your deployment expects a **Bearer access token** on gRPC (for example via a gateway that validates OIDC tokens). Register your IdP application with a **redirect URI** that matches `DIRECTORY_CLIENT_OIDC_REDIRECT_URI` exactly (for example `http://localhost:8484/callback`). The SDK starts a short-lived HTTP server on loopback to receive the authorization redirect.
118
+
119
+ Some IdPs use **public clients** with PKCE; your IdP may still expect a `client_secret` field in configuration. In that case, use a **random placeholder** from environment variables, not a real secret in source code.
120
+
121
+ **Important:** The default in-repo Envoy authorization stack validates **GitHub** tokens. OIDC access tokens from your IdP only work if your environment’s gateway or auth service is configured to accept them.
122
+
123
+ ```bash
124
+ export DIRECTORY_CLIENT_AUTH_MODE="oidc"
125
+ export DIRECTORY_CLIENT_SERVER_ADDRESS="directory.example.com:443"
126
+ export DIRECTORY_CLIENT_OIDC_ISSUER="https://your-idp-provider.example.com"
127
+ export DIRECTORY_CLIENT_OIDC_CLIENT_ID="your-app-client-id"
128
+ # Optional placeholder for public clients:
129
+ export DIRECTORY_CLIENT_OIDC_CLIENT_SECRET="random-non-secret-string"
130
+ export DIRECTORY_CLIENT_OIDC_REDIRECT_URI="http://localhost:8484/callback"
131
+ # Optional: comma-separated scopes
132
+ # export DIRECTORY_CLIENT_OIDC_SCOPES="openid,profile,email"
133
+ ```
134
+
135
+ ```js
136
+ import { Client } from 'agntcy-dir';
137
+
138
+ // After exporting the variables above (or building a Config with authMode: 'oidc'):
139
+ const client = new Client();
140
+ await client.authenticateOAuthPkce();
141
+ ```
142
+
143
+ For custom transports, call `Client.createGRPCTransport(oidcConfig, { oidcTokenHolder })` with an `OAuthTokenHolder` (exported from this package). The usual path is `new Client(oidcConfig)`, which wires the holder and transport automatically.
144
+
108
145
  ## Getting Started
109
146
 
110
147
  ### Prerequisites
@@ -9,6 +9,8 @@ import type { Message } from '@bufbuild/protobuf';
9
9
  import type { Timestamp } from '@bufbuild/protobuf/wkt';
10
10
  import { Transport } from '@connectrpc/connect';
11
11
 
12
+ export declare type AuthMode = '' | 'x509' | 'jwt' | 'tls' | 'oidc';
13
+
12
14
  /**
13
15
  * Supporting credential type definitions
14
16
  *
@@ -32,6 +34,35 @@ declare type BasicAuthCredentials = Message<"agntcy.dir.store.v1.BasicAuthCreden
32
34
  */
33
35
  declare const BasicAuthCredentialsSchema: GenMessage<BasicAuthCredentials>;
34
36
 
37
+ export declare class CachedToken {
38
+ accessToken: string;
39
+ tokenType: string;
40
+ provider: string;
41
+ issuer: string;
42
+ refreshToken: string;
43
+ expiresAt: Date | undefined;
44
+ user: string;
45
+ userId: string;
46
+ email: string;
47
+ createdAt: Date | undefined;
48
+ constructor(accessToken: string, tokenType?: string, provider?: string, issuer?: string, refreshToken?: string, expiresAt?: Date | undefined, user?: string, userId?: string, email?: string, createdAt?: Date | undefined);
49
+ static fromJson(payload: CachedTokenJson): CachedToken;
50
+ toJson(): Record<string, string>;
51
+ }
52
+
53
+ declare interface CachedTokenJson {
54
+ access_token: string;
55
+ token_type?: string;
56
+ provider?: string;
57
+ issuer?: string;
58
+ refresh_token?: string;
59
+ expires_at?: string;
60
+ user?: string;
61
+ user_id?: string;
62
+ email?: string;
63
+ created_at?: string;
64
+ }
65
+
35
66
  /**
36
67
  * High-level client for interacting with AGNTCY Directory services.
37
68
  *
@@ -62,6 +93,7 @@ export declare class Client {
62
93
  syncClient: Client_2<typeof models_2.store_v1.SyncService>;
63
94
  eventClient: Client_2<typeof models_2.events_v1.EventService>;
64
95
  namingClient: Client_2<typeof models_2.naming_v1.NamingService>;
96
+ private oauthHolder;
65
97
  /**
66
98
  * Initialize the client with the given configuration.
67
99
  *
@@ -87,10 +119,21 @@ export declare class Client {
87
119
  constructor(config?: Config);
88
120
  constructor(config?: Config, grpcTransport?: Transport);
89
121
  private static convertToPEM;
90
- static createGRPCTransport(config: Config): Promise<Transport>;
122
+ private static secureNodeOptions;
123
+ private static createOidcTransport;
124
+ static createGRPCTransport(config: Config, oidcOptions?: {
125
+ oidcTokenHolder: OAuthTokenHolder;
126
+ }): Promise<Transport>;
91
127
  private static createX509Transport;
92
128
  private static createJWTTransport;
93
129
  private static createTLSTransport;
130
+ private cachedTokenFromResponse;
131
+ /**
132
+ * Run browser-based OAuth 2.0 Authorization Code + PKCE login (loopback callback).
133
+ *
134
+ * Requires `authMode: 'oidc'`, `oidcIssuer`, and `oidcClientId`.
135
+ */
136
+ authenticateOAuthPkce(): Promise<void>;
94
137
  /**
95
138
  * Request generator helper function for streaming requests.
96
139
  */
@@ -357,6 +400,8 @@ export declare class Client {
357
400
  * The verification process uses the external dirctl command-line tool
358
401
  * to perform the actual cryptographic operations.
359
402
  *
403
+ * When fromServer is true, uses the server's cached verification result.
404
+ *
360
405
  * @param request - VerifyRequest containing the record reference and verification parameters.
361
406
  * The provider can specify either key-based verification (with a public key)
362
407
  * or OIDC-based verification
@@ -373,7 +418,8 @@ export declare class Client {
373
418
  * console.log(`Signature valid: ${response.success}`);
374
419
  * ```
375
420
  */
376
- verify(request: models_2.sign_v1.VerifyRequest): models_2.sign_v1.VerifyResponse;
421
+ verify(request: models_2.sign_v1.VerifyRequest): Promise<models_2.sign_v1.VerifyResponse>;
422
+ private _verifyViaServer;
377
423
  /**
378
424
  * Create a new synchronization configuration.
379
425
  *
@@ -655,28 +701,50 @@ export declare class Config {
655
701
  static DEFAULT_DIRCTL_PATH: string;
656
702
  static DEFAULT_SPIFFE_ENDPOINT_SOCKET: string;
657
703
  static DEFAULT_AUTH_MODE: string;
704
+ static DEFAULT_AUTH_TOKEN: string;
658
705
  static DEFAULT_JWT_AUDIENCE: string;
659
706
  static DEFAULT_TLS_CA_FILE: string;
660
707
  static DEFAULT_TLS_CERT_FILE: string;
661
708
  static DEFAULT_TLS_KEY_FILE: string;
709
+ static DEFAULT_TLS_SERVER_NAME: string;
710
+ static DEFAULT_TLS_SKIP_VERIFY: boolean;
711
+ static DEFAULT_OIDC_ISSUER: string;
712
+ static DEFAULT_OIDC_CLIENT_ID: string;
713
+ static DEFAULT_OIDC_CLIENT_SECRET: string;
714
+ static DEFAULT_OIDC_REDIRECT_URI: string;
715
+ static DEFAULT_OIDC_CALLBACK_PORT: number;
716
+ static DEFAULT_OIDC_AUTH_TIMEOUT: number;
717
+ static DEFAULT_OIDC_SCOPES: string[];
662
718
  serverAddress: string;
663
719
  dirctlPath: string;
664
720
  spiffeEndpointSocket: string;
665
- authMode: '' | 'x509' | 'jwt' | 'tls';
721
+ authMode: AuthMode;
722
+ authToken: string;
723
+ /** Backward-compatible alias for `authToken`. */
724
+ oidcAccessToken: string;
666
725
  jwtAudience: string;
667
726
  tlsCaFile: string;
668
727
  tlsCertFile: string;
669
728
  tlsKeyFile: string;
729
+ tlsServerName: string;
730
+ tlsSkipVerify: boolean;
731
+ oidcIssuer: string;
732
+ oidcClientId: string;
733
+ oidcClientSecret: string;
734
+ oidcRedirectUri: string;
735
+ oidcCallbackPort: number;
736
+ oidcAuthTimeout: number;
737
+ oidcScopes: string[];
670
738
  /**
671
739
  * Creates a new Config instance.
672
740
  *
673
741
  * @param serverAddress - The server address to connect to. Defaults to '127.0.0.1:8888'
674
742
  * @param dirctlPath - Path to the dirctl executable. Defaults to 'dirctl'
675
743
  * @param spiffeEndpointSocket - Path to the spire server socket. Defaults to empty string.
676
- * @param authMode - Authentication mode: '' for insecure, 'x509', 'jwt' or 'tls'. Defaults to ''
744
+ * @param authMode - Authentication mode: '' for insecure, 'x509', 'jwt', 'tls', or 'oidc'. Defaults to ''
677
745
  * @param jwtAudience - JWT audience for JWT authentication. Required when authMode is 'jwt'
678
746
  */
679
- constructor(serverAddress?: string, dirctlPath?: string, spiffeEndpointSocket?: string, authMode?: '' | 'x509' | 'jwt' | 'tls', jwtAudience?: string, tlsCaFile?: string, tlsCertFile?: string, tlsKeyFile?: string);
747
+ constructor(serverAddress?: string, dirctlPath?: string, spiffeEndpointSocket?: string, authMode?: AuthMode, jwtAudience?: string, tlsCaFile?: string, tlsCertFile?: string, tlsKeyFile?: string, authToken?: string, tlsServerName?: string, tlsSkipVerify?: boolean, oidcIssuer?: string, oidcClientId?: string, oidcClientSecret?: string, oidcRedirectUri?: string, oidcCallbackPort?: number, oidcAuthTimeout?: number, oidcScopes?: string[] | undefined, oidcAccessToken?: string | undefined);
680
748
  /**
681
749
  * Load configuration from environment variables.
682
750
  *
@@ -790,6 +858,58 @@ declare type CreateSyncResponse = Message<"agntcy.dir.store.v1.CreateSyncRespons
790
858
  */
791
859
  declare const CreateSyncResponseSchema: GenMessage<CreateSyncResponse>;
792
860
 
861
+ /**
862
+ * @generated from message agntcy.dir.store.v1.DeleteReferrerRequest
863
+ */
864
+ declare type DeleteReferrerRequest = Message<"agntcy.dir.store.v1.DeleteReferrerRequest"> & {
865
+ /**
866
+ * The record the referrer(s) are referring to.
867
+ *
868
+ * @generated from field: agntcy.dir.core.v1.RecordRef record = 1;
869
+ */
870
+ record?: RecordRef;
871
+
872
+ /**
873
+ * The CID of the referrer to delete.
874
+ * If set, delete the referrer by CID.
875
+ *
876
+ * @generated from field: optional agntcy.dir.core.v1.ReferrerRef referrer_ref = 2;
877
+ */
878
+ referrerRef?: ReferrerRef;
879
+
880
+ /**
881
+ * The referrer type of the referrers to delete.
882
+ * If set, delete the referrers with given type.
883
+ *
884
+ * @generated from field: optional string referrer_type = 3;
885
+ */
886
+ referrerType?: string;
887
+ };
888
+
889
+ /**
890
+ * Describes the message agntcy.dir.store.v1.DeleteReferrerRequest.
891
+ * Use `create(DeleteReferrerRequestSchema)` to create a new message.
892
+ */
893
+ declare const DeleteReferrerRequestSchema: GenMessage<DeleteReferrerRequest>;
894
+
895
+ /**
896
+ * @generated from message agntcy.dir.store.v1.DeleteReferrerResponse
897
+ */
898
+ declare type DeleteReferrerResponse = Message<"agntcy.dir.store.v1.DeleteReferrerResponse"> & {
899
+ /**
900
+ * The CID(s) of the deleted referrers.
901
+ *
902
+ * @generated from field: repeated agntcy.dir.core.v1.ReferrerRef referrer_refs = 1;
903
+ */
904
+ referrerRefs: ReferrerRef[];
905
+ };
906
+
907
+ /**
908
+ * Describes the message agntcy.dir.store.v1.DeleteReferrerResponse.
909
+ * Use `create(DeleteReferrerResponseSchema)` to create a new message.
910
+ */
911
+ declare const DeleteReferrerResponseSchema: GenMessage<DeleteReferrerResponse>;
912
+
793
913
  /**
794
914
  * DeleteSyncRequest specifies which synchronization to delete.
795
915
  *
@@ -1693,6 +1813,17 @@ declare const NamingService: GenService<{
1693
1813
  },
1694
1814
  }>;
1695
1815
 
1816
+ export declare class OAuthPkceError extends Error {
1817
+ constructor(message: string);
1818
+ }
1819
+
1820
+ export declare class OAuthTokenHolder {
1821
+ private accessToken;
1822
+ setTokens(accessToken: string): void;
1823
+ updateFromTokenResponse(payload: Record<string, unknown>): void;
1824
+ getAccessToken(): string;
1825
+ }
1826
+
1696
1827
  /**
1697
1828
  * @generated from message agntcy.dir.routing.v1.Peer
1698
1829
  */
@@ -1949,6 +2080,13 @@ declare type PullReferrerRequest = Message<"agntcy.dir.store.v1.PullReferrerRequ
1949
2080
  * @generated from field: optional string referrer_type = 2;
1950
2081
  */
1951
2082
  referrerType?: string;
2083
+
2084
+ /**
2085
+ * If set, return the given referrer.
2086
+ *
2087
+ * @generated from field: optional agntcy.dir.core.v1.ReferrerRef referrer_ref = 3;
2088
+ */
2089
+ referrerRef?: ReferrerRef;
1952
2090
  };
1953
2091
 
1954
2092
  /**
@@ -1991,11 +2129,34 @@ declare type PushReferrerRequest = Message<"agntcy.dir.store.v1.PushReferrerRequ
1991
2129
  recordRef?: RecordRef;
1992
2130
 
1993
2131
  /**
1994
- * RecordReferrer object to be stored for the record
2132
+ * The type of the referrer.
2133
+ * For example, "agntcy.dir.sign.v1.Signature" for signatures.
1995
2134
  *
1996
- * @generated from field: agntcy.dir.core.v1.RecordReferrer referrer = 2;
2135
+ * @generated from field: string type = 2;
1997
2136
  */
1998
- referrer?: RecordReferrer;
2137
+ type: string;
2138
+
2139
+ /**
2140
+ * Annotations attached to the referrer object.
2141
+ *
2142
+ * @generated from field: map<string, string> annotations = 3;
2143
+ */
2144
+ annotations: { [key: string]: string };
2145
+
2146
+ /**
2147
+ * Creation timestamp of the record in the RFC3339 format.
2148
+ * Specs: https://www.rfc-editor.org/rfc/rfc3339.html
2149
+ *
2150
+ * @generated from field: string created_at = 4;
2151
+ */
2152
+ createdAt: string;
2153
+
2154
+ /**
2155
+ * The actual data of the referrer.
2156
+ *
2157
+ * @generated from field: google.protobuf.Struct data = 5;
2158
+ */
2159
+ data?: JsonObject;
1999
2160
  };
2000
2161
 
2001
2162
  /**
@@ -2023,6 +2184,13 @@ declare type PushReferrerResponse = Message<"agntcy.dir.store.v1.PushReferrerRes
2023
2184
  * @generated from field: optional string error_message = 2;
2024
2185
  */
2025
2186
  errorMessage?: string;
2187
+
2188
+ /**
2189
+ * The CID of the referrer
2190
+ *
2191
+ * @generated from field: agntcy.dir.core.v1.ReferrerRef referrer_ref = 3;
2192
+ */
2193
+ referrerRef?: ReferrerRef;
2026
2194
  };
2027
2195
 
2028
2196
  /**
@@ -2291,6 +2459,14 @@ declare enum RecordQueryType {
2291
2459
  * @generated from enum value: RECORD_QUERY_TYPE_VERIFIED = 13;
2292
2460
  */
2293
2461
  VERIFIED = 13,
2462
+
2463
+ /**
2464
+ * Query for trusted records (signature verification passed).
2465
+ * Boolean field - use "true" or "false" as value.
2466
+ *
2467
+ * @generated from enum value: RECORD_QUERY_TYPE_TRUSTED = 14;
2468
+ */
2469
+ TRUSTED = 14,
2294
2470
  }
2295
2471
 
2296
2472
  /**
@@ -2407,6 +2583,13 @@ declare type RecordReferrer = Message<"agntcy.dir.core.v1.RecordReferrer"> & {
2407
2583
  * @generated from field: google.protobuf.Struct data = 5;
2408
2584
  */
2409
2585
  data?: JsonObject;
2586
+
2587
+ /**
2588
+ * The CID of the referrer.
2589
+ *
2590
+ * @generated from field: agntcy.dir.core.v1.ReferrerRef referrer_ref = 6;
2591
+ */
2592
+ referrerRef?: ReferrerRef;
2410
2593
  };
2411
2594
 
2412
2595
  /**
@@ -2443,6 +2626,19 @@ declare const RecordRefsSchema: GenMessage<RecordRefs>;
2443
2626
  */
2444
2627
  declare const RecordSchema: GenMessage<Record_2>;
2445
2628
 
2629
+ /**
2630
+ * @generated from message agntcy.dir.core.v1.ReferrerRef
2631
+ */
2632
+ declare type ReferrerRef = Message<"agntcy.dir.core.v1.ReferrerRef"> & {
2633
+ /**
2634
+ * Content Identifier (https://github.com/multiformats/cid)
2635
+ * A self-describing, content-addressed identifier
2636
+ *
2637
+ * @generated from field: string cid = 1;
2638
+ */
2639
+ cid: string;
2640
+ };
2641
+
2446
2642
  /**
2447
2643
  * @generated from message agntcy.dir.store.v1.RequestRegistryCredentialsRequest
2448
2644
  */
@@ -3371,6 +3567,10 @@ export declare namespace store_v1 {
3371
3567
  PullReferrerRequestSchema,
3372
3568
  PullReferrerResponse,
3373
3569
  PullReferrerResponseSchema,
3570
+ DeleteReferrerRequest,
3571
+ DeleteReferrerRequestSchema,
3572
+ DeleteReferrerResponse,
3573
+ DeleteReferrerResponseSchema,
3374
3574
  StoreService,
3375
3575
  file_agntcy_dir_store_v1_sync_service,
3376
3576
  CreateSyncRequest,
@@ -3481,6 +3681,16 @@ declare const StoreService: GenService<{
3481
3681
  input: typeof PullReferrerRequestSchema;
3482
3682
  output: typeof PullReferrerResponseSchema;
3483
3683
  },
3684
+ /**
3685
+ * DeleteReferrer performs delete operation for record referrers.
3686
+ *
3687
+ * @generated from rpc agntcy.dir.store.v1.StoreService.DeleteReferrer
3688
+ */
3689
+ deleteReferrer: {
3690
+ methodKind: "bidi_streaming";
3691
+ input: typeof DeleteReferrerRequestSchema;
3692
+ output: typeof DeleteReferrerResponseSchema;
3693
+ },
3484
3694
  }>;
3485
3695
 
3486
3696
  /**
@@ -3614,6 +3824,19 @@ declare enum SyncStatus {
3614
3824
  */
3615
3825
  declare const SyncStatusSchema: GenEnum<SyncStatus>;
3616
3826
 
3827
+ export declare const TOKEN_CACHE_FILE = "auth-token.json";
3828
+
3829
+ export declare class TokenCache {
3830
+ readonly cacheDir: string;
3831
+ constructor(cacheDir?: string);
3832
+ getCachePath(): string;
3833
+ load(): CachedToken | undefined;
3834
+ save(token: CachedToken): void;
3835
+ clear(): void;
3836
+ isValid(token: CachedToken | undefined): boolean;
3837
+ getValidToken(): CachedToken | undefined;
3838
+ }
3839
+
3617
3840
  /**
3618
3841
  * @generated from message agntcy.dir.routing.v1.UnpublishRequest
3619
3842
  */
@@ -3753,6 +3976,14 @@ declare type VerifyRequest = Message<"agntcy.dir.sign.v1.VerifyRequest"> & {
3753
3976
  * @generated from field: agntcy.dir.sign.v1.VerifyRequestProvider provider = 2;
3754
3977
  */
3755
3978
  provider?: VerifyRequestProvider;
3979
+
3980
+ /**
3981
+ * When true, use cached verification result from server.
3982
+ * When false, verification is performed locally.
3983
+ *
3984
+ * @generated from field: bool from_server = 3;
3985
+ */
3986
+ fromServer: boolean;
3756
3987
  };
3757
3988
 
3758
3989
  /**