@enbox/auth 0.3.1

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.
Files changed (66) hide show
  1. package/dist/esm/auth-manager.js +496 -0
  2. package/dist/esm/auth-manager.js.map +1 -0
  3. package/dist/esm/events.js +65 -0
  4. package/dist/esm/events.js.map +1 -0
  5. package/dist/esm/flows/dwn-discovery.js +281 -0
  6. package/dist/esm/flows/dwn-discovery.js.map +1 -0
  7. package/dist/esm/flows/dwn-registration.js +122 -0
  8. package/dist/esm/flows/dwn-registration.js.map +1 -0
  9. package/dist/esm/flows/import-identity.js +175 -0
  10. package/dist/esm/flows/import-identity.js.map +1 -0
  11. package/dist/esm/flows/local-connect.js +141 -0
  12. package/dist/esm/flows/local-connect.js.map +1 -0
  13. package/dist/esm/flows/session-restore.js +109 -0
  14. package/dist/esm/flows/session-restore.js.map +1 -0
  15. package/dist/esm/flows/wallet-connect.js +199 -0
  16. package/dist/esm/flows/wallet-connect.js.map +1 -0
  17. package/dist/esm/identity-session.js +33 -0
  18. package/dist/esm/identity-session.js.map +1 -0
  19. package/dist/esm/index.js +50 -0
  20. package/dist/esm/index.js.map +1 -0
  21. package/dist/esm/storage/storage.js +152 -0
  22. package/dist/esm/storage/storage.js.map +1 -0
  23. package/dist/esm/types.js +30 -0
  24. package/dist/esm/types.js.map +1 -0
  25. package/dist/esm/vault/vault-manager.js +95 -0
  26. package/dist/esm/vault/vault-manager.js.map +1 -0
  27. package/dist/types/auth-manager.d.ts +176 -0
  28. package/dist/types/auth-manager.d.ts.map +1 -0
  29. package/dist/types/events.d.ts +36 -0
  30. package/dist/types/events.d.ts.map +1 -0
  31. package/dist/types/flows/dwn-discovery.d.ts +157 -0
  32. package/dist/types/flows/dwn-discovery.d.ts.map +1 -0
  33. package/dist/types/flows/dwn-registration.d.ts +39 -0
  34. package/dist/types/flows/dwn-registration.d.ts.map +1 -0
  35. package/dist/types/flows/import-identity.d.ts +35 -0
  36. package/dist/types/flows/import-identity.d.ts.map +1 -0
  37. package/dist/types/flows/local-connect.d.ts +29 -0
  38. package/dist/types/flows/local-connect.d.ts.map +1 -0
  39. package/dist/types/flows/session-restore.d.ts +27 -0
  40. package/dist/types/flows/session-restore.d.ts.map +1 -0
  41. package/dist/types/flows/wallet-connect.d.ts +44 -0
  42. package/dist/types/flows/wallet-connect.d.ts.map +1 -0
  43. package/dist/types/identity-session.d.ts +52 -0
  44. package/dist/types/identity-session.d.ts.map +1 -0
  45. package/dist/types/index.d.ts +45 -0
  46. package/dist/types/index.d.ts.map +1 -0
  47. package/dist/types/storage/storage.d.ts +54 -0
  48. package/dist/types/storage/storage.d.ts.map +1 -0
  49. package/dist/types/types.d.ts +312 -0
  50. package/dist/types/types.d.ts.map +1 -0
  51. package/dist/types/vault/vault-manager.d.ts +57 -0
  52. package/dist/types/vault/vault-manager.d.ts.map +1 -0
  53. package/package.json +71 -0
  54. package/src/auth-manager.ts +569 -0
  55. package/src/events.ts +66 -0
  56. package/src/flows/dwn-discovery.ts +300 -0
  57. package/src/flows/dwn-registration.ts +157 -0
  58. package/src/flows/import-identity.ts +217 -0
  59. package/src/flows/local-connect.ts +171 -0
  60. package/src/flows/session-restore.ts +135 -0
  61. package/src/flows/wallet-connect.ts +225 -0
  62. package/src/identity-session.ts +65 -0
  63. package/src/index.ts +89 -0
  64. package/src/storage/storage.ts +136 -0
  65. package/src/types.ts +388 -0
  66. package/src/vault/vault-manager.ts +89 -0
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Local DID connect flow.
3
+ *
4
+ * Creates or reconnects a local identity with vault-protected keys.
5
+ * This replaces the "Mode D/E" paths in Enbox.connect().
6
+ * @module
7
+ */
8
+
9
+ import type { EnboxUserAgent } from '@enbox/agent';
10
+
11
+ import type { AuthEventEmitter } from '../events.js';
12
+ import type { LocalConnectOptions, RegistrationOptions, StorageAdapter, SyncOption } from '../types.js';
13
+
14
+ import { applyLocalDwnDiscovery } from './dwn-discovery.js';
15
+ import { AuthSession } from '../identity-session.js';
16
+ import { registerWithDwnEndpoints } from './dwn-registration.js';
17
+ import { INSECURE_DEFAULT_PASSWORD, STORAGE_KEYS } from '../types.js';
18
+
19
+ /** @internal */
20
+ export interface LocalConnectContext {
21
+ userAgent: EnboxUserAgent;
22
+ emitter: AuthEventEmitter;
23
+ storage: StorageAdapter;
24
+ defaultPassword?: string;
25
+ defaultSync?: SyncOption;
26
+ defaultDwnEndpoints?: string[];
27
+ registration?: RegistrationOptions;
28
+ }
29
+
30
+ /**
31
+ * Execute the local connect flow.
32
+ *
33
+ * - On first launch: initializes the vault, creates a new DID, returns recovery phrase.
34
+ * - On subsequent launches: unlocks the vault and reconnects to the existing identity.
35
+ */
36
+ export async function localConnect(
37
+ ctx: LocalConnectContext,
38
+ options: LocalConnectOptions = {},
39
+ ): Promise<AuthSession> {
40
+ const { userAgent, emitter, storage } = ctx;
41
+
42
+ const password = options.password ?? ctx.defaultPassword ?? INSECURE_DEFAULT_PASSWORD;
43
+ const sync = options.sync ?? ctx.defaultSync;
44
+ const dwnEndpoints = options.dwnEndpoints ?? ctx.defaultDwnEndpoints ?? ['https://enbox-dwn.fly.dev'];
45
+
46
+ // Warn if using insecure default.
47
+ if (password === INSECURE_DEFAULT_PASSWORD) {
48
+ console.warn(
49
+ '[@enbox/auth] SECURITY WARNING: No password set. Using insecure default. ' +
50
+ 'Set a password via AuthManager.create({ password }) or connect({ password }) ' +
51
+ 'to protect your identity vault.'
52
+ );
53
+ }
54
+
55
+ let recoveryPhrase: string | undefined;
56
+
57
+ // Initialize vault on first launch.
58
+ if (await userAgent.firstLaunch()) {
59
+ recoveryPhrase = await userAgent.initialize({
60
+ password,
61
+ recoveryPhrase: options.recoveryPhrase,
62
+ dwnEndpoints,
63
+ });
64
+ }
65
+
66
+ // Start the agent (unlocks vault if locked, sets agentDid).
67
+ await userAgent.start({ password });
68
+ emitter.emit('vault-unlocked', {});
69
+
70
+ // Apply local DWN discovery (browser redirect payload or persisted endpoint).
71
+ await applyLocalDwnDiscovery(userAgent, storage, emitter);
72
+
73
+ // Find or create the user identity.
74
+ const identities = await userAgent.identity.list();
75
+ let identity = identities[0];
76
+ let isNewIdentity = false;
77
+
78
+ if (!identity) {
79
+ isNewIdentity = true;
80
+ identity = await userAgent.identity.create({
81
+ didMethod : 'dht',
82
+ metadata : { name: options.metadata?.name ?? 'Default' },
83
+ didOptions : {
84
+ services: [
85
+ {
86
+ id : 'dwn',
87
+ type : 'DecentralizedWebNode',
88
+ serviceEndpoint : dwnEndpoints,
89
+ enc : '#enc',
90
+ sig : '#sig',
91
+ }
92
+ ],
93
+ verificationMethods: [
94
+ {
95
+ algorithm : 'Ed25519',
96
+ id : 'sig',
97
+ purposes : ['assertionMethod', 'authentication'],
98
+ },
99
+ {
100
+ algorithm : 'X25519',
101
+ id : 'enc',
102
+ purposes : ['keyAgreement'],
103
+ },
104
+ ],
105
+ },
106
+ });
107
+ }
108
+
109
+ const connectedDid = identity.metadata.connectedDid ?? identity.did.uri;
110
+ const delegateDid = identity.metadata.connectedDid ? identity.did.uri : undefined;
111
+
112
+ // Register with DWN endpoints (if registration options are provided).
113
+ if (ctx.registration) {
114
+ await registerWithDwnEndpoints(
115
+ {
116
+ userAgent : userAgent,
117
+ dwnEndpoints,
118
+ agentDid : userAgent.agentDid.uri,
119
+ connectedDid,
120
+ },
121
+ ctx.registration,
122
+ );
123
+ }
124
+
125
+ // Register sync for new identities.
126
+ if (isNewIdentity && sync !== 'off') {
127
+ await userAgent.sync.registerIdentity({
128
+ did : connectedDid,
129
+ options : { delegateDid, protocols: [] },
130
+ });
131
+ }
132
+
133
+ // Start sync.
134
+ if (sync !== 'off') {
135
+ const syncMode = sync === undefined ? 'live' : 'poll';
136
+ const syncInterval = sync ?? (syncMode === 'live' ? '5m' : '2m');
137
+ userAgent.sync.startSync({ mode: syncMode, interval: syncInterval })
138
+ .catch((error: unknown) => {
139
+ console.error('[@enbox/auth] Sync failed:', error);
140
+ });
141
+ }
142
+
143
+ // Persist session info.
144
+ await storage.set(STORAGE_KEYS.PREVIOUSLY_CONNECTED, 'true');
145
+ await storage.set(STORAGE_KEYS.ACTIVE_IDENTITY, connectedDid);
146
+
147
+ const identityInfo = {
148
+ didUri : connectedDid,
149
+ name : identity.metadata.name,
150
+ connectedDid : identity.metadata.connectedDid,
151
+ };
152
+
153
+ const session = new AuthSession({
154
+ agent : userAgent,
155
+ did : connectedDid,
156
+ delegateDid,
157
+ recoveryPhrase,
158
+ identity : identityInfo,
159
+ });
160
+
161
+ emitter.emit('identity-added', { identity: identityInfo });
162
+ emitter.emit('session-start', {
163
+ session: {
164
+ did : session.did,
165
+ delegateDid,
166
+ identity : identityInfo,
167
+ },
168
+ });
169
+
170
+ return session;
171
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Session restore flow.
3
+ *
4
+ * Restores a previously established session from persisted storage,
5
+ * replacing the "previouslyConnected" pattern in apps.
6
+ * @module
7
+ */
8
+
9
+ import type { EnboxUserAgent } from '@enbox/agent';
10
+
11
+ import type { AuthEventEmitter } from '../events.js';
12
+ import type { RestoreSessionOptions, StorageAdapter, SyncOption } from '../types.js';
13
+
14
+ import { applyLocalDwnDiscovery } from './dwn-discovery.js';
15
+ import { AuthSession } from '../identity-session.js';
16
+ import { INSECURE_DEFAULT_PASSWORD, STORAGE_KEYS } from '../types.js';
17
+
18
+ /** @internal */
19
+ export interface SessionRestoreContext {
20
+ userAgent: EnboxUserAgent;
21
+ emitter: AuthEventEmitter;
22
+ storage: StorageAdapter;
23
+ defaultPassword?: string;
24
+ defaultSync?: SyncOption;
25
+ }
26
+
27
+ /**
28
+ * Attempt to restore a previous session.
29
+ *
30
+ * Returns `undefined` if no previous session exists.
31
+ * Returns an `AuthSession` if the session was successfully restored.
32
+ */
33
+ export async function restoreSession(
34
+ ctx: SessionRestoreContext,
35
+ options: RestoreSessionOptions = {},
36
+ ): Promise<AuthSession | undefined> {
37
+ const { userAgent, emitter, storage } = ctx;
38
+
39
+ // Check if there was a previous session.
40
+ const previouslyConnected = await storage.get(STORAGE_KEYS.PREVIOUSLY_CONNECTED);
41
+ if (previouslyConnected !== 'true') {
42
+ return undefined;
43
+ }
44
+
45
+ const password = options.password ?? ctx.defaultPassword ?? INSECURE_DEFAULT_PASSWORD;
46
+
47
+ // Warn if using insecure default.
48
+ if (password === INSECURE_DEFAULT_PASSWORD) {
49
+ console.warn(
50
+ '[@enbox/auth] SECURITY WARNING: No password set. Using insecure default. ' +
51
+ 'Set a password to protect your identity vault.'
52
+ );
53
+ }
54
+
55
+ // Start the agent (initializes + unlocks vault).
56
+ if (await userAgent.firstLaunch()) {
57
+ // Vault doesn't exist yet — this shouldn't happen if previouslyConnected is true.
58
+ // Clean up the stale flag and return undefined.
59
+ await storage.remove(STORAGE_KEYS.PREVIOUSLY_CONNECTED);
60
+ return undefined;
61
+ }
62
+
63
+ await userAgent.start({ password });
64
+ emitter.emit('vault-unlocked', {});
65
+
66
+ // Apply local DWN discovery (browser redirect payload or persisted endpoint).
67
+ await applyLocalDwnDiscovery(userAgent, storage, emitter);
68
+
69
+ // Determine which identity to reconnect.
70
+ const activeIdentityDid = await storage.get(STORAGE_KEYS.ACTIVE_IDENTITY);
71
+ const storedDelegateDid = await storage.get(STORAGE_KEYS.DELEGATE_DID);
72
+
73
+ // First try the connected identity (wallet-connected sessions).
74
+ let identity = await userAgent.identity.connectedIdentity();
75
+
76
+ if (!identity) {
77
+ // Try to find the specific active identity.
78
+ if (activeIdentityDid) {
79
+ identity = await userAgent.identity.get({ didUri: activeIdentityDid });
80
+ }
81
+
82
+ // Fall back to the first available identity.
83
+ if (!identity) {
84
+ const identities = await userAgent.identity.list();
85
+ identity = identities[0];
86
+ }
87
+ }
88
+
89
+ if (!identity) {
90
+ // No identity found — clean up stale session data.
91
+ await storage.remove(STORAGE_KEYS.PREVIOUSLY_CONNECTED);
92
+ await storage.remove(STORAGE_KEYS.ACTIVE_IDENTITY);
93
+ await storage.remove(STORAGE_KEYS.DELEGATE_DID);
94
+ await storage.remove(STORAGE_KEYS.CONNECTED_DID);
95
+ return undefined;
96
+ }
97
+
98
+ const connectedDid = identity.metadata.connectedDid ?? identity.did.uri;
99
+ const delegateDid = identity.metadata.connectedDid
100
+ ? identity.did.uri
101
+ : (storedDelegateDid ?? undefined);
102
+
103
+ // Start sync.
104
+ const sync = ctx.defaultSync;
105
+ if (sync !== 'off') {
106
+ const syncMode = sync === undefined ? 'live' : 'poll';
107
+ const syncInterval = sync ?? (syncMode === 'live' ? '5m' : '2m');
108
+ userAgent.sync.startSync({ mode: syncMode, interval: syncInterval })
109
+ .catch((err: unknown) => {
110
+ console.error('[@enbox/auth] Sync failed:', err);
111
+ });
112
+ }
113
+
114
+ // Update persisted session info.
115
+ await storage.set(STORAGE_KEYS.ACTIVE_IDENTITY, connectedDid);
116
+
117
+ const identityInfo = {
118
+ didUri : connectedDid,
119
+ name : identity.metadata.name,
120
+ connectedDid : identity.metadata.connectedDid,
121
+ };
122
+
123
+ const session = new AuthSession({
124
+ agent : userAgent,
125
+ did : connectedDid,
126
+ delegateDid,
127
+ identity : identityInfo,
128
+ });
129
+
130
+ emitter.emit('session-start', {
131
+ session: { did: connectedDid, delegateDid, identity: identityInfo },
132
+ });
133
+
134
+ return session;
135
+ }
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Wallet connect (OIDC/QR) flow.
3
+ *
4
+ * Connects to an external wallet via the WalletConnect relay protocol,
5
+ * importing a delegated DID with permission grants.
6
+ * This replaces the "Mode B/C" paths in Enbox.connect().
7
+ * @module
8
+ */
9
+
10
+ import { Convert } from '@enbox/common';
11
+ import { WalletConnect } from '@enbox/agent';
12
+ import type { DwnDataEncodedRecordsWriteMessage, DwnMessagesPermissionScope, DwnRecordsPermissionScope, EnboxUserAgent } from '@enbox/agent';
13
+ import { DwnInterface, DwnPermissionGrant } from '@enbox/agent';
14
+
15
+ import type { AuthEventEmitter } from '../events.js';
16
+ import { AuthSession } from '../identity-session.js';
17
+ import { registerWithDwnEndpoints } from './dwn-registration.js';
18
+ import { STORAGE_KEYS } from '../types.js';
19
+ import type { RegistrationOptions, StorageAdapter, SyncOption, WalletConnectOptions } from '../types.js';
20
+
21
+ /** @internal */
22
+ export interface WalletConnectContext {
23
+ userAgent: EnboxUserAgent;
24
+ emitter: AuthEventEmitter;
25
+ storage: StorageAdapter;
26
+ defaultSync?: SyncOption;
27
+ defaultDwnEndpoints?: string[];
28
+ registration?: RegistrationOptions;
29
+ }
30
+
31
+ /**
32
+ * Process connected grants by storing them in the local DWN as the owner.
33
+ *
34
+ * This is the agent-level equivalent of `Enbox.processConnectedGrants()`.
35
+ * It stores each grant, signed as owner, and returns the deduplicated
36
+ * list of protocol URIs represented by the grants.
37
+ *
38
+ * @internal
39
+ */
40
+ export async function processConnectedGrants(params: {
41
+ agent: EnboxUserAgent;
42
+ delegateDid: string;
43
+ grants: DwnDataEncodedRecordsWriteMessage[];
44
+ }): Promise<string[]> {
45
+ const { agent, delegateDid, grants } = params;
46
+ const connectedProtocols = new Set<string>();
47
+
48
+ for (const grantMessage of grants) {
49
+ const grant = DwnPermissionGrant.parse(grantMessage);
50
+
51
+ // Store the grant as the owner of the DWN so the delegateDid
52
+ // can use it when impersonating the connectedDid.
53
+ const { encodedData, ...rawMessage } = grantMessage;
54
+ const dataStream = new Blob([Convert.base64Url(encodedData).toUint8Array() as BlobPart]);
55
+
56
+ const { reply } = await agent.processDwnRequest({
57
+ store : true,
58
+ author : delegateDid,
59
+ target : delegateDid,
60
+ messageType : DwnInterface.RecordsWrite,
61
+ signAsOwner : true,
62
+ rawMessage,
63
+ dataStream,
64
+ });
65
+
66
+ if (reply.status.code !== 202) {
67
+ throw new Error(
68
+ `[@enbox/auth] Failed to process connected grant: ${reply.status.detail}`
69
+ );
70
+ }
71
+
72
+ const protocol = (grant.scope as DwnMessagesPermissionScope | DwnRecordsPermissionScope).protocol;
73
+ if (protocol) {
74
+ connectedProtocols.add(protocol);
75
+ }
76
+ }
77
+
78
+ return [...connectedProtocols];
79
+ }
80
+
81
+ /**
82
+ * Execute the wallet connect flow.
83
+ *
84
+ * 1. Passes the permission requests directly to `WalletConnect.initClient()`.
85
+ * 2. Imports the delegate DID and processes grants.
86
+ * 3. Sets up sync and returns an AuthSession.
87
+ */
88
+ export async function walletConnect(
89
+ ctx: WalletConnectContext,
90
+ options: WalletConnectOptions,
91
+ ): Promise<AuthSession> {
92
+ const { userAgent, emitter, storage } = ctx;
93
+ const sync = options.sync ?? ctx.defaultSync;
94
+
95
+ if (sync === 'off') {
96
+ throw new Error(
97
+ '[@enbox/auth] Sync must be enabled when using wallet connect. ' +
98
+ 'Remove sync: "off" or set an interval like "15s".'
99
+ );
100
+ }
101
+
102
+ // Run the full OIDC wallet connect flow.
103
+ // permissionRequests are already agent-level ConnectPermissionRequest objects.
104
+ const result = await WalletConnect.initClient({
105
+ displayName : options.displayName,
106
+ connectServerUrl : options.connectServerUrl,
107
+ walletUri : options.walletUri ?? 'web5://connect',
108
+ permissionRequests : options.permissionRequests,
109
+ onWalletUriReady : options.onWalletUriReady,
110
+ validatePin : options.validatePin,
111
+ });
112
+
113
+ if (!result) {
114
+ throw new Error('[@enbox/auth] Wallet connect flow was cancelled or returned no result.');
115
+ }
116
+
117
+ const { delegatePortableDid, connectedDid, delegateGrants } = result;
118
+
119
+ // Import the delegated DID as an Identity.
120
+ let identity;
121
+ try {
122
+ identity = await userAgent.identity.import({
123
+ portableIdentity: {
124
+ portableDid : delegatePortableDid,
125
+ metadata : {
126
+ connectedDid,
127
+ name : 'Default',
128
+ uri : delegatePortableDid.uri,
129
+ tenant : userAgent.agentDid.uri,
130
+ },
131
+ },
132
+ });
133
+
134
+ // Process the connected grants using agent primitives.
135
+ const connectedProtocols = await processConnectedGrants({
136
+ agent : userAgent,
137
+ delegateDid : delegatePortableDid.uri,
138
+ grants : delegateGrants,
139
+ });
140
+
141
+ // Register with DWN endpoints (if registration options are provided).
142
+ if (ctx.registration) {
143
+ const dwnEndpoints = ctx.defaultDwnEndpoints ?? ['https://enbox-dwn.fly.dev'];
144
+ await registerWithDwnEndpoints(
145
+ {
146
+ userAgent : userAgent,
147
+ dwnEndpoints,
148
+ agentDid : userAgent.agentDid.uri,
149
+ connectedDid,
150
+ },
151
+ ctx.registration,
152
+ );
153
+ }
154
+
155
+ // Register sync for the connected identity.
156
+ await userAgent.sync.registerIdentity({
157
+ did : connectedDid,
158
+ options : {
159
+ delegateDid : delegatePortableDid.uri,
160
+ protocols : connectedProtocols,
161
+ },
162
+ });
163
+
164
+ // Pull down existing messages from the connected DID's DWN.
165
+ await userAgent.sync.sync('pull');
166
+ } catch (error: unknown) {
167
+ // Clean up on failure.
168
+ if (identity) {
169
+ try {
170
+ await userAgent.did.delete({
171
+ didUri : identity.did.uri,
172
+ tenant : identity.metadata.tenant,
173
+ deleteKey : true,
174
+ });
175
+ } catch { /* best effort */ }
176
+
177
+ try {
178
+ await userAgent.identity.delete({ didUri: identity.did.uri });
179
+ } catch { /* best effort */ }
180
+ }
181
+
182
+ const message = error instanceof Error ? error.message : String(error);
183
+ throw new Error(`[@enbox/auth] Wallet connect failed: ${message}`);
184
+ }
185
+
186
+ // Start sync.
187
+ const syncMode = sync === undefined ? 'live' : 'poll';
188
+ const syncInterval = sync ?? (syncMode === 'live' ? '5m' : '2m');
189
+ userAgent.sync.startSync({ mode: syncMode, interval: syncInterval })
190
+ .catch((err: unknown) => {
191
+ console.error('[@enbox/auth] Sync failed:', err);
192
+ });
193
+
194
+ const delegateDid = delegatePortableDid.uri;
195
+
196
+ // Persist session info.
197
+ await storage.set(STORAGE_KEYS.PREVIOUSLY_CONNECTED, 'true');
198
+ await storage.set(STORAGE_KEYS.ACTIVE_IDENTITY, connectedDid);
199
+ await storage.set(STORAGE_KEYS.DELEGATE_DID, delegateDid);
200
+ await storage.set(STORAGE_KEYS.CONNECTED_DID, connectedDid);
201
+
202
+ const identityInfo = {
203
+ didUri : connectedDid,
204
+ name : identity.metadata.name,
205
+ connectedDid : identity.metadata.connectedDid,
206
+ };
207
+
208
+ const session = new AuthSession({
209
+ agent : userAgent,
210
+ did : connectedDid,
211
+ delegateDid,
212
+ identity : identityInfo,
213
+ });
214
+
215
+ emitter.emit('identity-added', { identity: identityInfo });
216
+ emitter.emit('session-start', {
217
+ session: {
218
+ did : session.did,
219
+ delegateDid,
220
+ identity : identityInfo,
221
+ },
222
+ });
223
+
224
+ return session;
225
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * AuthSession represents an active, authenticated session with a specific identity.
3
+ * @module
4
+ */
5
+
6
+ import type { EnboxAgent } from '@enbox/agent';
7
+
8
+ import type { IdentityInfo } from './types.js';
9
+
10
+ /**
11
+ * An active, authenticated session bound to a specific identity.
12
+ *
13
+ * The session exposes the authenticated **agent**, **did**, and
14
+ * **delegateDid** — the primitives needed to interact with the DWN
15
+ * network. Consumers that use `@enbox/api` can construct an `Enbox`
16
+ * instance from these properties:
17
+ *
18
+ * ```ts
19
+ * import { Enbox } from '@enbox/api';
20
+ *
21
+ * const session = await auth.connect();
22
+ * const enbox = Enbox.connect({
23
+ * agent: session.agent,
24
+ * connectedDid: session.did,
25
+ * delegateDid: session.delegateDid,
26
+ * });
27
+ * ```
28
+ */
29
+ export class AuthSession {
30
+ /** The authenticated Enbox agent managing keys, DIDs, and DWN access. */
31
+ readonly agent: EnboxAgent;
32
+
33
+ /** The DID URI of the connected identity. */
34
+ readonly did: string;
35
+
36
+ /**
37
+ * The delegate DID URI, present when connected via wallet connect.
38
+ * This is the locally-created DID that holds delegated permissions
39
+ * from the wallet's identity.
40
+ */
41
+ readonly delegateDid?: string;
42
+
43
+ /**
44
+ * The BIP-39 recovery phrase, present only on first-time local connect.
45
+ * Should be shown to the user for backup and then discarded from memory.
46
+ */
47
+ readonly recoveryPhrase?: string;
48
+
49
+ /** Metadata about the connected identity. */
50
+ readonly identity: IdentityInfo;
51
+
52
+ constructor(params: {
53
+ agent: EnboxAgent;
54
+ did: string;
55
+ delegateDid?: string;
56
+ recoveryPhrase?: string;
57
+ identity: IdentityInfo;
58
+ }) {
59
+ this.agent = params.agent;
60
+ this.did = params.did;
61
+ this.delegateDid = params.delegateDid;
62
+ this.recoveryPhrase = params.recoveryPhrase;
63
+ this.identity = params.identity;
64
+ }
65
+ }
package/src/index.ts ADDED
@@ -0,0 +1,89 @@
1
+ /**
2
+ * @enbox/auth — Headless authentication and identity management SDK.
3
+ *
4
+ * Provides composable, multi-identity-aware authentication that works
5
+ * in both browser and CLI environments. Depends only on `@enbox/agent`
6
+ * and can be used standalone or consumed by `@enbox/api`.
7
+ *
8
+ * @example Standalone auth
9
+ * ```ts
10
+ * import { AuthManager } from '@enbox/auth';
11
+ *
12
+ * const auth = await AuthManager.create({ sync: '15s' });
13
+ * const session = await auth.restoreSession() ?? await auth.connect();
14
+ *
15
+ * // session.agent — the authenticated Enbox agent
16
+ * // session.did — the connected DID URI
17
+ * ```
18
+ *
19
+ * @example With @enbox/api
20
+ * ```ts
21
+ * import { AuthManager } from '@enbox/auth';
22
+ * import { Enbox } from '@enbox/api';
23
+ *
24
+ * const auth = await AuthManager.create({ sync: '15s' });
25
+ * const session = await auth.connect();
26
+ *
27
+ * const enbox = Enbox.connect({
28
+ * agent: session.agent,
29
+ * connectedDid: session.did,
30
+ * delegateDid: session.delegateDid,
31
+ * });
32
+ * ```
33
+ *
34
+ * @packageDocumentation
35
+ */
36
+
37
+ // Core classes
38
+ export { AuthManager } from './auth-manager.js';
39
+ export { AuthSession } from './identity-session.js';
40
+ export { VaultManager } from './vault/vault-manager.js';
41
+ export { AuthEventEmitter } from './events.js';
42
+
43
+ // Re-export agent classes so consumers can construct custom agents/vaults
44
+ // without a direct @enbox/agent dependency.
45
+ export { EnboxUserAgent, HdIdentityVault } from '@enbox/agent';
46
+
47
+ // Wallet-connect helpers
48
+ export { processConnectedGrants } from './flows/wallet-connect.js';
49
+
50
+ // Local DWN discovery (browser dwn:// protocol integration)
51
+ export {
52
+ applyLocalDwnDiscovery,
53
+ checkUrlForDwnDiscoveryPayload,
54
+ clearLocalDwnEndpoint,
55
+ persistLocalDwnEndpoint,
56
+ probeLocalDwn,
57
+ requestLocalDwnDiscovery,
58
+ restoreLocalDwnEndpoint,
59
+ } from './flows/dwn-discovery.js';
60
+
61
+ // Storage adapters
62
+ export { BrowserStorage, LevelStorage, MemoryStorage, createDefaultStorage } from './storage/storage.js';
63
+
64
+ // Types
65
+ export type {
66
+ AuthEvent,
67
+ AuthEventHandler,
68
+ AuthEventMap,
69
+ AuthManagerOptions,
70
+ AuthSessionInfo,
71
+ AuthState,
72
+ ConnectPermissionRequest,
73
+ DisconnectOptions,
74
+ IdentityInfo,
75
+ IdentityVaultBackup,
76
+ ImportFromPhraseOptions,
77
+ ImportFromPortableOptions,
78
+ LocalConnectOptions,
79
+ LocalDwnStrategy,
80
+ PortableIdentity,
81
+ ProviderAuthParams,
82
+ ProviderAuthResult,
83
+ RegistrationOptions,
84
+ RegistrationTokenData,
85
+ RestoreSessionOptions,
86
+ StorageAdapter,
87
+ SyncOption,
88
+ WalletConnectOptions,
89
+ } from './types.js';