@oxyhq/core 12.10.6 → 12.11.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.
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/HttpService.js +66 -6
- package/dist/cjs/boot/sessionColdBoot.js +142 -37
- package/dist/cjs/i18n/locales/ar-SA.json +13 -1
- package/dist/cjs/i18n/locales/ca-ES.json +13 -1
- package/dist/cjs/i18n/locales/de-DE.json +13 -1
- package/dist/cjs/i18n/locales/en-US.json +13 -4
- package/dist/cjs/i18n/locales/es-ES.json +13 -4
- package/dist/cjs/i18n/locales/fr-FR.json +13 -1
- package/dist/cjs/i18n/locales/it-IT.json +13 -1
- package/dist/cjs/i18n/locales/ja-JP.json +13 -1
- package/dist/cjs/i18n/locales/ko-KR.json +13 -1
- package/dist/cjs/i18n/locales/locales/ar-SA.json +13 -1
- package/dist/cjs/i18n/locales/locales/ca-ES.json +13 -1
- package/dist/cjs/i18n/locales/locales/de-DE.json +13 -1
- package/dist/cjs/i18n/locales/locales/en-US.json +13 -4
- package/dist/cjs/i18n/locales/locales/es-ES.json +13 -4
- package/dist/cjs/i18n/locales/locales/fr-FR.json +13 -1
- package/dist/cjs/i18n/locales/locales/it-IT.json +13 -1
- package/dist/cjs/i18n/locales/locales/ja-JP.json +13 -1
- package/dist/cjs/i18n/locales/locales/ko-KR.json +13 -1
- package/dist/cjs/i18n/locales/locales/pt-PT.json +13 -1
- package/dist/cjs/i18n/locales/locales/zh-CN.json +13 -1
- package/dist/cjs/i18n/locales/pt-PT.json +13 -1
- package/dist/cjs/i18n/locales/zh-CN.json +13 -1
- package/dist/cjs/index.js +31 -5
- package/dist/cjs/mixins/OxyServices.auth.js +257 -17
- package/dist/cjs/mixins/OxyServices.deviceBoot.js +54 -3
- package/dist/cjs/mixins/OxyServices.notifications.js +63 -0
- package/dist/cjs/mixins/OxyServices.privacy.js +6 -0
- package/dist/cjs/mixins/OxyServices.user.js +1 -0
- package/dist/cjs/mixins/index.js +5 -0
- package/dist/cjs/session/SessionClient.js +40 -4
- package/dist/cjs/session/accountDialogController.js +288 -41
- package/dist/cjs/session/identityPin.js +256 -0
- package/dist/cjs/session/identitySession.js +135 -0
- package/dist/cjs/session/projectSessionState.js +54 -15
- package/dist/cjs/session/refresh.js +73 -8
- package/dist/cjs/utils/commonsDelivery.js +59 -0
- package/dist/cjs/utils/oauthPkce.js +33 -3
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/HttpService.js +66 -6
- package/dist/esm/boot/sessionColdBoot.js +142 -37
- package/dist/esm/i18n/locales/ar-SA.json +13 -1
- package/dist/esm/i18n/locales/ca-ES.json +13 -1
- package/dist/esm/i18n/locales/de-DE.json +13 -1
- package/dist/esm/i18n/locales/en-US.json +13 -4
- package/dist/esm/i18n/locales/es-ES.json +13 -4
- package/dist/esm/i18n/locales/fr-FR.json +13 -1
- package/dist/esm/i18n/locales/it-IT.json +13 -1
- package/dist/esm/i18n/locales/ja-JP.json +13 -1
- package/dist/esm/i18n/locales/ko-KR.json +13 -1
- package/dist/esm/i18n/locales/locales/ar-SA.json +13 -1
- package/dist/esm/i18n/locales/locales/ca-ES.json +13 -1
- package/dist/esm/i18n/locales/locales/de-DE.json +13 -1
- package/dist/esm/i18n/locales/locales/en-US.json +13 -4
- package/dist/esm/i18n/locales/locales/es-ES.json +13 -4
- package/dist/esm/i18n/locales/locales/fr-FR.json +13 -1
- package/dist/esm/i18n/locales/locales/it-IT.json +13 -1
- package/dist/esm/i18n/locales/locales/ja-JP.json +13 -1
- package/dist/esm/i18n/locales/locales/ko-KR.json +13 -1
- package/dist/esm/i18n/locales/locales/pt-PT.json +13 -1
- package/dist/esm/i18n/locales/locales/zh-CN.json +13 -1
- package/dist/esm/i18n/locales/pt-PT.json +13 -1
- package/dist/esm/i18n/locales/zh-CN.json +13 -1
- package/dist/esm/index.js +14 -1
- package/dist/esm/mixins/OxyServices.auth.js +257 -17
- package/dist/esm/mixins/OxyServices.deviceBoot.js +52 -3
- package/dist/esm/mixins/OxyServices.notifications.js +60 -0
- package/dist/esm/mixins/OxyServices.privacy.js +6 -0
- package/dist/esm/mixins/OxyServices.user.js +1 -0
- package/dist/esm/mixins/index.js +5 -0
- package/dist/esm/session/SessionClient.js +40 -4
- package/dist/esm/session/accountDialogController.js +288 -41
- package/dist/esm/session/identityPin.js +249 -0
- package/dist/esm/session/identitySession.js +131 -0
- package/dist/esm/session/projectSessionState.js +54 -15
- package/dist/esm/session/refresh.js +73 -8
- package/dist/esm/utils/commonsDelivery.js +54 -0
- package/dist/esm/utils/oauthPkce.js +31 -2
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/HttpService.d.ts +18 -1
- package/dist/types/boot/sessionColdBoot.d.ts +38 -1
- package/dist/types/index.d.ts +12 -4
- package/dist/types/mixins/OxyServices.auth.d.ts +262 -11
- package/dist/types/mixins/OxyServices.deviceBoot.d.ts +31 -1
- package/dist/types/mixins/OxyServices.notifications.d.ts +143 -0
- package/dist/types/mixins/OxyServices.user.d.ts +2 -0
- package/dist/types/mixins/index.d.ts +2 -1
- package/dist/types/session/SessionClient.d.ts +28 -0
- package/dist/types/session/accountDialogController.d.ts +187 -9
- package/dist/types/session/identityPin.d.ts +87 -0
- package/dist/types/session/identitySession.d.ts +105 -0
- package/dist/types/session/projectSessionState.d.ts +21 -19
- package/dist/types/session/refresh.d.ts +32 -1
- package/dist/types/utils/commonsDelivery.d.ts +105 -0
- package/dist/types/utils/oauthPkce.d.ts +21 -1
- package/package.json +3 -3
- package/src/HttpService.ts +67 -6
- package/src/__tests__/inSessionRefresh.test.ts +67 -0
- package/src/boot/__tests__/sessionColdBoot.identity.test.ts +393 -0
- package/src/boot/sessionColdBoot.ts +183 -37
- package/src/i18n/locales/ar-SA.json +13 -1
- package/src/i18n/locales/ca-ES.json +13 -1
- package/src/i18n/locales/de-DE.json +13 -1
- package/src/i18n/locales/en-US.json +13 -4
- package/src/i18n/locales/es-ES.json +13 -4
- package/src/i18n/locales/fr-FR.json +13 -1
- package/src/i18n/locales/it-IT.json +13 -1
- package/src/i18n/locales/ja-JP.json +13 -1
- package/src/i18n/locales/ko-KR.json +13 -1
- package/src/i18n/locales/pt-PT.json +13 -1
- package/src/i18n/locales/zh-CN.json +13 -1
- package/src/index.ts +49 -0
- package/src/mixins/OxyServices.auth.ts +464 -24
- package/src/mixins/OxyServices.deviceBoot.ts +54 -2
- package/src/mixins/OxyServices.notifications.ts +142 -0
- package/src/mixins/OxyServices.privacy.ts +6 -0
- package/src/mixins/OxyServices.user.ts +3 -0
- package/src/mixins/__tests__/commonsSignIn.test.ts +754 -2
- package/src/mixins/__tests__/deviceTokenMintPinned.test.ts +113 -0
- package/src/mixins/__tests__/preSessionSkipAuth.test.ts +18 -0
- package/src/mixins/__tests__/privacyCacheInvalidation.test.ts +2 -0
- package/src/mixins/index.ts +6 -0
- package/src/session/SessionClient.ts +57 -4
- package/src/session/__tests__/SessionClient.identityPin.test.ts +175 -0
- package/src/session/__tests__/accountDialogController.test.ts +812 -1
- package/src/session/__tests__/identityPin.test.ts +131 -0
- package/src/session/__tests__/identitySession.test.ts +194 -0
- package/src/session/__tests__/projectSessionState.test.ts +88 -0
- package/src/session/__tests__/refresh.identityPin.test.ts +306 -0
- package/src/session/accountDialogController.ts +435 -44
- package/src/session/identityPin.ts +310 -0
- package/src/session/identitySession.ts +206 -0
- package/src/session/projectSessionState.ts +61 -13
- package/src/session/refresh.ts +103 -9
- package/src/utils/__tests__/oauthPkce.test.ts +51 -0
- package/src/utils/commonsDelivery.ts +132 -0
- package/src/utils/oauthPkce.ts +56 -3
|
@@ -89,7 +89,15 @@ export declare class HttpService {
|
|
|
89
89
|
private logger;
|
|
90
90
|
private config;
|
|
91
91
|
private tokenRefreshPromise;
|
|
92
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Epoch ms of the last FAILED refresh (0 = none since the last success). The
|
|
94
|
+
* post-failure cooldown is measured from here; its length depends on whether
|
|
95
|
+
* the current token is still valid ({@link TOKEN_REFRESH_COOLDOWN_MS}) or
|
|
96
|
+
* already expired ({@link EXPIRED_TOKEN_REFRESH_COOLDOWN_MS}), so an expired
|
|
97
|
+
* token recovers promptly the instant it crosses `exp` — without storing a
|
|
98
|
+
* fixed deadline that could not shrink once the token expired mid-cooldown.
|
|
99
|
+
*/
|
|
100
|
+
private lastRefreshFailureAt;
|
|
93
101
|
private authRefreshHandler;
|
|
94
102
|
private accessTokenProvider;
|
|
95
103
|
private deviceSecretMintInFlight;
|
|
@@ -224,6 +232,15 @@ export declare class HttpService {
|
|
|
224
232
|
*/
|
|
225
233
|
private getAuthHeader;
|
|
226
234
|
refreshAccessToken(reason: AuthRefreshReason): Promise<string | null>;
|
|
235
|
+
/**
|
|
236
|
+
* Whether the CURRENT stored access token is already past its `exp`. Drives
|
|
237
|
+
* the shorter post-failure refresh cooldown ({@link EXPIRED_TOKEN_REFRESH_COOLDOWN_MS}):
|
|
238
|
+
* a still-valid (near-expiry) token can wait out the full cooldown, but an
|
|
239
|
+
* expired one must re-mint promptly. Returns `false` for an absent or
|
|
240
|
+
* opaque/no-`exp` token — no proof it is expired, so keep the conservative
|
|
241
|
+
* (longer) cooldown and avoid an unnecessary retry loop.
|
|
242
|
+
*/
|
|
243
|
+
private isAccessTokenExpired;
|
|
227
244
|
/**
|
|
228
245
|
* PROCESS-WIDE single-flight for the rotating device-secret mint
|
|
229
246
|
* (`POST /session/device/token`).
|
|
@@ -15,14 +15,34 @@
|
|
|
15
15
|
* origin persisted a `deviceId` + `deviceSecret`, mint a short access token
|
|
16
16
|
* with a single bearer-less POST to `/session/device/token` (no cookie, no
|
|
17
17
|
* navigation) and rotate the secret in-use.
|
|
18
|
-
* 3. `shared-key-signin` (native) — re-mint from the
|
|
18
|
+
* 3. `shared-key-signin` (native, ACCOUNT mode) — re-mint from the
|
|
19
|
+
* shared-keychain identity — OR `identity-key-signin` (IDENTITY mode) —
|
|
20
|
+
* re-mint from THIS device's primary identity key.
|
|
19
21
|
* 4. Signed out.
|
|
20
22
|
*
|
|
23
|
+
* Two session modes (see {@link RunSessionColdBootOptions.sessionMode}):
|
|
24
|
+
* - `account` (default) — the device's ACTIVE account owns the session. Every
|
|
25
|
+
* Oxy app but the identity vault boots this way; behaviour is unchanged.
|
|
26
|
+
* - `identity` — the owner of the local PRIMARY identity key owns the session,
|
|
27
|
+
* permanently, regardless of which account the device is switched to. Each
|
|
28
|
+
* step above is bound to the persisted identity pin, and the shared-keychain
|
|
29
|
+
* lane is replaced by the primary-key one (the shared slot is a CROSS-APP
|
|
30
|
+
* slot that may hold a different identity).
|
|
31
|
+
*
|
|
21
32
|
* ESM-safe (no `require()`); no react/react-native/expo imports.
|
|
22
33
|
*/
|
|
23
34
|
import { type ColdBootOutcome } from '../utils/coldBoot';
|
|
35
|
+
import { type IdentityBinding } from '../session/identitySession';
|
|
24
36
|
import type { OxyServices } from '../OxyServices';
|
|
25
37
|
import type { AuthStateStore } from '../session/authStateStore';
|
|
38
|
+
/**
|
|
39
|
+
* Who owns the session this boot resolves.
|
|
40
|
+
*
|
|
41
|
+
* - `account` — the device's active account (every ordinary Oxy app).
|
|
42
|
+
* - `identity` — the owner of the device's primary identity key (the identity
|
|
43
|
+
* vault). Requires {@link RunSessionColdBootOptions.identity}.
|
|
44
|
+
*/
|
|
45
|
+
export type SessionMode = 'account' | 'identity';
|
|
26
46
|
/** The winning session shape a cold-boot step reports. */
|
|
27
47
|
export interface DeviceBootSession {
|
|
28
48
|
sessionId: string;
|
|
@@ -71,6 +91,23 @@ export interface RunSessionColdBootOptions {
|
|
|
71
91
|
* so a flaky probe can never falsely skip a real sign-in.
|
|
72
92
|
*/
|
|
73
93
|
isOffline?: () => boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Who owns the resolved session. Defaults to `'account'` — the device's active
|
|
96
|
+
* account — which is the behaviour every ordinary Oxy app has today and which
|
|
97
|
+
* this option leaves byte-for-byte unchanged.
|
|
98
|
+
*
|
|
99
|
+
* `'identity'` binds the boot to the owner of this device's PRIMARY identity
|
|
100
|
+
* key and REQUIRES {@link identity}. When it is missing the boot refuses to
|
|
101
|
+
* run any lane (an identity-bound client silently falling back to the device's
|
|
102
|
+
* active account is precisely the bug this mode exists to prevent) and
|
|
103
|
+
* resolves signed out.
|
|
104
|
+
*/
|
|
105
|
+
sessionMode?: SessionMode;
|
|
106
|
+
/**
|
|
107
|
+
* The identity binding (pin store + key/signature access) used by
|
|
108
|
+
* `sessionMode: 'identity'`. Ignored in `'account'` mode.
|
|
109
|
+
*/
|
|
110
|
+
identity?: IdentityBinding;
|
|
74
111
|
}
|
|
75
112
|
/**
|
|
76
113
|
* Run the device-first cold boot. Resolves to the `runColdBoot` outcome and, as
|
package/dist/types/index.d.ts
CHANGED
|
@@ -23,8 +23,11 @@ export type { LinkedHttpClient } from './OxyServices.base';
|
|
|
23
23
|
export type { AuthRefreshReason, AuthRefreshHandler } from './HttpService';
|
|
24
24
|
export { ServiceCredentialMismatchError, } from './mixins/OxyServices.auth';
|
|
25
25
|
export { getCommonsApprovalBlockingReason, parseCommonsApprovalExpiresAt, } from './utils/commonsApproval';
|
|
26
|
+
export { selectCommonsDelivery, pushTargetsFromDelivery, commonsDeliveryPlatform } from './utils/commonsDelivery';
|
|
27
|
+
export type { CommonsDeliveryFacts, CommonsDeliveryPlatform, CommonsDeliveryRoute, } from './utils/commonsDelivery';
|
|
26
28
|
export type { ServiceTokenResponse } from './mixins/OxyServices.auth';
|
|
27
|
-
export type { CommonsSignInHandle, CommonsSignInStatus, CommonsApprovalInfo, CommonsSignInActionResult, } from './mixins/OxyServices.auth';
|
|
29
|
+
export type { CommonsSignInHandle, CommonsSignInStatus, CommonsSignInPurpose, CommonsOAuthContext, CommonsApprovalInfo, CommonsApprovalSubjectAccount, CommonsSignInActionResult, CommonsDenyReason, CommonsOAuthFinalizeResult, CommonsDeliveryResult, } from './mixins/OxyServices.auth';
|
|
30
|
+
export type { PushTokenPlatform, RegisterPushTokenInput, } from './mixins/OxyServices.notifications';
|
|
28
31
|
export type { ServiceApp, ServiceActingAsVerification } from './mixins/OxyServices.utility';
|
|
29
32
|
export type { ContactDiscoveryMatch, ContactDiscoveryResponse, } from './mixins/OxyServices.contacts';
|
|
30
33
|
export type { InitDeviceTransferResult, DeviceTransferOutcome, } from './mixins/OxyServices.deviceTransfer';
|
|
@@ -93,7 +96,7 @@ export { CENTRAL_IDP_APEX } from './utils/authWebUrl';
|
|
|
93
96
|
export { isOxyRpOrigin } from './utils/webauthnOrigin';
|
|
94
97
|
export { runColdBoot } from './utils/coldBoot';
|
|
95
98
|
export type { ColdBootStep, ColdBootStepResult, ColdBootSession, ColdBootSkip, ColdBootOutcome, RunColdBootOptions, } from './utils/coldBoot';
|
|
96
|
-
export { buildOAuthAuthorizeUrl, computeCodeChallenge, generateOAuthState, generatePkcePair, DEFAULT_OAUTH_SCOPE, OXY_AUTHORIZE_URL, OXY_OAUTH_STATE_STORAGE_KEY, OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY, OXY_SILENT_OAUTH_ATTEMPTED_KEY, OXY_CROSS_ORIGIN_RESTORE_ATTEMPTED_KEY, OXY_OAUTH_RETURN_PATH_STORAGE_KEY, normalizeOAuthRedirectUri, persistOAuthHandshake, readOAuthHandshake, clearOAuthHandshake, persistOAuthReturnPath, consumeOAuthReturnPath, } from './utils/oauthPkce';
|
|
99
|
+
export { buildOAuthAuthorizeUrl, computeCodeChallenge, generateOAuthState, generatePkcePair, DEFAULT_OAUTH_SCOPE, OXY_AUTHORIZE_URL, OXY_OAUTH_STATE_STORAGE_KEY, OXY_OAUTH_CODE_VERIFIER_STORAGE_KEY, OXY_OAUTH_REDIRECT_URI_STORAGE_KEY, OXY_SILENT_OAUTH_ATTEMPTED_KEY, OXY_CROSS_ORIGIN_RESTORE_ATTEMPTED_KEY, OXY_OAUTH_RETURN_PATH_STORAGE_KEY, normalizeOAuthRedirectUri, canonicalizeOAuthRedirectUri, persistOAuthHandshake, readOAuthHandshake, clearOAuthHandshake, persistOAuthReturnPath, consumeOAuthReturnPath, } from './utils/oauthPkce';
|
|
97
100
|
export type { PkcePair, BuildOAuthAuthorizeUrlParams } from './utils/oauthPkce';
|
|
98
101
|
export { buildIdpHubOrigin, buildHubSyncUrl, isIdpHubOrigin, isLoopbackOrigin, isOfficialWebOrigin, isAllowedDeviceJoinOrigin, normalizeOfficialReturnOrigin, parseHubSyncReturnUrl, } from './utils/officialOrigins';
|
|
99
102
|
export { syncHubAfterSignIn, redeemHubTicketOnHub, } from './session/hubSync';
|
|
@@ -107,13 +110,18 @@ export { deviceStateToClientSessions, activeSessionIdOf, activeUserOf, accountId
|
|
|
107
110
|
export { projectSwitchableAccounts, switchableAccountIds, } from './session/accountProjection';
|
|
108
111
|
export type { SwitchableAccount, SwitchableAccountUser, ProjectSwitchableAccountsInput, } from './session/accountProjection';
|
|
109
112
|
export { AccountDialogController, createAccountDialogController, } from './session/accountDialogController';
|
|
110
|
-
export type { AccountDialogControllerOptions, AccountDialogSnapshot, AccountDialogView, CommonsAvailability, PopupWindowHandle, SignInFlowPhase, SignInFlowState, } from './session/accountDialogController';
|
|
113
|
+
export type { AccountDialogControllerOptions, AccountDialogSnapshot, AccountDialogView, CommonsAvailability, PopupWindowHandle, SignInFlowPhase, SignInFlowState, SignInProgress, } from './session/accountDialogController';
|
|
111
114
|
export { createWebAuthStateStore, createNativeAuthStateStore, createMemoryAuthStateStore, AUTH_STATE_STORAGE_KEY, } from './session/authStateStore';
|
|
112
115
|
export type { PersistedAuthState, AuthStateStore, NativeKeyValueStorage, } from './session/authStateStore';
|
|
116
|
+
export { createWebIdentityPinStore, createNativeIdentityPinStore, createMemoryIdentityPinStore, identityPinMatches, IDENTITY_PIN_STORAGE_KEY, } from './session/identityPin';
|
|
117
|
+
export type { IdentityPin, IdentityPinStore } from './session/identityPin';
|
|
118
|
+
export { resolveIdentityPin, establishIdentitySession, } from './session/identitySession';
|
|
119
|
+
export type { IdentityBinding, IdentityRequestOptions, EstablishedIdentitySession, } from './session/identitySession';
|
|
120
|
+
export { AccountNotOnDeviceError } from './mixins/OxyServices.deviceBoot';
|
|
113
121
|
export { refreshPersistedSession, refreshDeviceSecretArm, createAuthRefreshHandler, installAuthRefreshHandler, startTokenRefreshScheduler, TOKEN_REFRESH_LEAD_MS, } from './session/refresh';
|
|
114
122
|
export type { RefreshDeps, TokenRefreshSchedulerHandle, DeviceSecretMintOutcome } from './session/refresh';
|
|
115
123
|
export { runSessionColdBoot } from './boot/sessionColdBoot';
|
|
116
|
-
export type { RunSessionColdBootOptions, SignedOutReason, DeviceBootSession, } from './boot/sessionColdBoot';
|
|
124
|
+
export type { RunSessionColdBootOptions, SessionMode, SignedOutReason, DeviceBootSession, } from './boot/sessionColdBoot';
|
|
117
125
|
export { packageInfo } from './constants/version';
|
|
118
126
|
import { OxyServices } from './OxyServices';
|
|
119
127
|
export default OxyServices;
|
|
@@ -32,12 +32,57 @@ export interface PublicKeyCheckResponse {
|
|
|
32
32
|
registered: boolean;
|
|
33
33
|
message: string;
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* How a "Sign in with Oxy" request finalizes once the approver authorizes it.
|
|
37
|
+
*
|
|
38
|
+
* ONE request (`AuthSession`) serves every delivery surface — popup, push, QR,
|
|
39
|
+
* deep link — so the purpose describes the FINALIZATION, never the transport:
|
|
40
|
+
*
|
|
41
|
+
* - `device_sign_in` — the classic device flow. The initiator exchanges its
|
|
42
|
+
* secret `sessionToken` for the first access token via `claimSessionByToken`.
|
|
43
|
+
* - `oauth_authorization` — the request additionally carries an OAuth binding
|
|
44
|
+
* ({@link CommonsOAuthContext}), so it finalizes into a single-use
|
|
45
|
+
* authorization CODE via {@link OxyServicesAuthMixin.finalizeCommonsOAuth}.
|
|
46
|
+
* The caller still performs the PKCE token exchange itself.
|
|
47
|
+
*/
|
|
48
|
+
export type CommonsSignInPurpose = 'device_sign_in' | 'oauth_authorization';
|
|
49
|
+
/**
|
|
50
|
+
* OAuth binding attached to a "Sign in with Oxy" request so a single
|
|
51
|
+
* `AuthSession` can finalize into a standard OAuth authorization code instead of
|
|
52
|
+
* a device-flow session.
|
|
53
|
+
*
|
|
54
|
+
* Only the minimum request binding is carried here — everything else (the app's
|
|
55
|
+
* name, icon, registered redirect URIs, trust flags) is owned server-side by the
|
|
56
|
+
* `Application` the `clientId` resolves to and is never client-supplied.
|
|
57
|
+
*
|
|
58
|
+
* The PKCE `codeVerifier` NEVER appears here: only its S256 `codeChallenge`
|
|
59
|
+
* crosses the wire, exactly as in the redirect flow. The RP-owned OAuth `state`
|
|
60
|
+
* also stays with the relying party, which validates it locally.
|
|
61
|
+
*/
|
|
62
|
+
export interface CommonsOAuthContext {
|
|
63
|
+
/** Exact registered redirect URI the authorization code will be returned to. */
|
|
64
|
+
redirectUri: string;
|
|
65
|
+
/** PKCE `BASE64URL(SHA-256(codeVerifier))` (RFC 7636 §4.2); the verifier stays client-side. */
|
|
66
|
+
codeChallenge: string;
|
|
67
|
+
/** PKCE transformation method. Always `S256` — `plain` is not accepted. */
|
|
68
|
+
codeChallengeMethod: 'S256';
|
|
69
|
+
/** Space-delimited OAuth scope string; the server normalizes and validates it. */
|
|
70
|
+
scope?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Optional delegated account the application will act AS (an organization or
|
|
73
|
+
* project the identity is a member of). The identity approving the request
|
|
74
|
+
* does not change; the server verifies the identity's permission to act as
|
|
75
|
+
* this account before finalizing.
|
|
76
|
+
*/
|
|
77
|
+
subjectAccountId?: string;
|
|
78
|
+
}
|
|
35
79
|
/**
|
|
36
80
|
* Handle returned by {@link OxyServicesAuthMixin.startCommonsSignIn} for a
|
|
37
81
|
* relying-party app initiating a "Sign in with Oxy" flow.
|
|
38
82
|
*
|
|
39
83
|
* `sessionToken` is the SECRET, high-entropy device-flow credential — it stays
|
|
40
|
-
* on the initiating client, is exchanged once via `claimSessionByToken
|
|
84
|
+
* on the initiating client, is exchanged once via `claimSessionByToken` (device
|
|
85
|
+
* sign-in) or {@link OxyServicesAuthMixin.finalizeCommonsOAuth} (OAuth), and is
|
|
41
86
|
* NEVER placed in the QR/deep-link. `authorizeCode` is the PUBLIC handle carried
|
|
42
87
|
* in `qrPayload`; the approver (Commons) resolves it via
|
|
43
88
|
* {@link OxyServicesAuthMixin.getCommonsApprovalInfo}.
|
|
@@ -54,16 +99,77 @@ export interface CommonsSignInHandle {
|
|
|
54
99
|
/** Session lifecycle status as reported by the server (e.g. `'pending'`). */
|
|
55
100
|
status: string;
|
|
56
101
|
}
|
|
57
|
-
/**
|
|
102
|
+
/**
|
|
103
|
+
* Poll result for a "Sign in with Oxy" device-flow session
|
|
104
|
+
* (`GET /auth/session/status`).
|
|
105
|
+
*
|
|
106
|
+
* The authoritative state machine stays small — `pending → authorized →
|
|
107
|
+
* consumed`, plus `cancelled` / `expired` — and lives in `status`. Delivery
|
|
108
|
+
* PROGRESS (`pushSentAt`, `openedAt`) is carried as timestamps beside it, never
|
|
109
|
+
* as competing statuses, so a progress signal can never be mistaken for an
|
|
110
|
+
* authorization.
|
|
111
|
+
*/
|
|
58
112
|
export interface CommonsSignInStatus {
|
|
59
113
|
/** True once an approver has authorized the session. */
|
|
60
114
|
authorized: boolean;
|
|
61
|
-
/** The authorized session id (present once `authorized`). */
|
|
115
|
+
/** The authorized session id (present once `authorized` for device sign-in). */
|
|
62
116
|
sessionId?: string;
|
|
63
117
|
/** The approving identity's public key (present once `authorized`). */
|
|
64
118
|
publicKey?: string;
|
|
65
119
|
/** Lifecycle status (`'pending'` | `'authorized'` | `'cancelled'` | `'expired'`). */
|
|
66
120
|
status?: string;
|
|
121
|
+
/**
|
|
122
|
+
* How this request finalizes. Unrecognized/missing values degrade to
|
|
123
|
+
* `device_sign_in` so an older API never misroutes an OAuth finalize.
|
|
124
|
+
*/
|
|
125
|
+
purpose?: CommonsSignInPurpose;
|
|
126
|
+
/**
|
|
127
|
+
* ISO-8601 timestamp of when the request was pushed to a known Commons
|
|
128
|
+
* installation, or `null` when no push has been sent (including on a server
|
|
129
|
+
* that predates delivery progress). Progress only — it never implies the push
|
|
130
|
+
* was received, opened, or approved.
|
|
131
|
+
*/
|
|
132
|
+
pushSentAt: string | null;
|
|
133
|
+
/**
|
|
134
|
+
* ISO-8601 timestamp of when the approval route was opened in Commons, or
|
|
135
|
+
* `null` when it has not been opened. Reported by the approver via
|
|
136
|
+
* {@link OxyServicesAuthMixin.markCommonsApprovalOpened}; it is an
|
|
137
|
+
* un-authenticated progress hint used only to advance the waiting UI, and is
|
|
138
|
+
* NEVER evidence that the request was approved.
|
|
139
|
+
*/
|
|
140
|
+
openedAt: string | null;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Outcome of asking Oxy to deliver a pending sign-in request to the identity's
|
|
144
|
+
* known Commons installations (`POST /auth/session/deliver/:authorizeCode`).
|
|
145
|
+
*
|
|
146
|
+
* `targets: 0` is a NORMAL outcome, not a failure: it simply means no capable
|
|
147
|
+
* Commons installation is registered, so push is not a usable route and the
|
|
148
|
+
* caller shows the QR instead. Feed `targets` into `selectCommonsDelivery`
|
|
149
|
+
* (`utils/commonsDelivery`) rather than branching on it ad hoc.
|
|
150
|
+
*/
|
|
151
|
+
export interface CommonsDeliveryResult {
|
|
152
|
+
/** Whether the server dispatched the request to at least one installation. */
|
|
153
|
+
delivered: boolean;
|
|
154
|
+
/** How many eligible Commons installations it was dispatched to (`0` is normal). */
|
|
155
|
+
targets: number;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* The account an application will act AS once the request is approved, when the
|
|
159
|
+
* request delegates to an organization/project rather than the approver's own
|
|
160
|
+
* personal account. Resolved and sanitized server-side from the request's
|
|
161
|
+
* `subjectAccountId`, so it is safe to display in the approval UI.
|
|
162
|
+
*
|
|
163
|
+
* The identity approving stays the identity: Commons renders this as a distinct
|
|
164
|
+
* "will act as" line, never as a change of who is signing.
|
|
165
|
+
*/
|
|
166
|
+
export interface CommonsApprovalSubjectAccount {
|
|
167
|
+
/** The delegated account's id. */
|
|
168
|
+
id: string;
|
|
169
|
+
/** The delegated account's handle. */
|
|
170
|
+
username: string;
|
|
171
|
+
/** Optional human-readable name; absent when the account has no real name. */
|
|
172
|
+
displayName?: string;
|
|
67
173
|
}
|
|
68
174
|
/**
|
|
69
175
|
* Server-resolved approval context shown by the approver (Commons) before
|
|
@@ -85,6 +191,32 @@ export interface CommonsApprovalInfo {
|
|
|
85
191
|
* "not verified") by {@link OxyServicesAuthMixin.getCommonsApprovalInfo}.
|
|
86
192
|
*/
|
|
87
193
|
originVerified: boolean;
|
|
194
|
+
/**
|
|
195
|
+
* COARSE, display-only label of the client that STARTED the request
|
|
196
|
+
* (`"Chrome on Windows"`), resolved server-side from the requesting browser —
|
|
197
|
+
* NEVER from the QR payload. Render it verbatim as a secondary line under the
|
|
198
|
+
* origin; it is the whole descriptor the platform has (no raw User-Agent, no
|
|
199
|
+
* IP, no location is ever collected for it).
|
|
200
|
+
*
|
|
201
|
+
* `null` whenever the server has no browser context to describe: native
|
|
202
|
+
* requesters, unidentifiable User-Agents, and any API that predates the field.
|
|
203
|
+
* Omit the line entirely in that case — never substitute a guess.
|
|
204
|
+
*/
|
|
205
|
+
requesterLabel: string | null;
|
|
206
|
+
/**
|
|
207
|
+
* How this request finalizes. Always present — an unrecognized or missing
|
|
208
|
+
* server value degrades to `'device_sign_in'`, the behaviour every server has
|
|
209
|
+
* always had, so an older API never makes the approver believe it is granting
|
|
210
|
+
* an OAuth authorization.
|
|
211
|
+
*/
|
|
212
|
+
purpose: CommonsSignInPurpose;
|
|
213
|
+
/**
|
|
214
|
+
* The delegated account the application will act as, or `null` when the
|
|
215
|
+
* request is for the approver's own account. Always present — a missing or
|
|
216
|
+
* malformed server value degrades to `null` (fail-safe to "no delegation"),
|
|
217
|
+
* so a partial payload can never imply a broader grant than was requested.
|
|
218
|
+
*/
|
|
219
|
+
subjectAccount: CommonsApprovalSubjectAccount | null;
|
|
88
220
|
/** Server-authoritative expiry (epoch ms or ISO-8601 string from the API). */
|
|
89
221
|
expiresAt: number | string;
|
|
90
222
|
/** Session lifecycle status. */
|
|
@@ -94,6 +226,33 @@ export interface CommonsApprovalInfo {
|
|
|
94
226
|
export interface CommonsSignInActionResult {
|
|
95
227
|
success: boolean;
|
|
96
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* Why the approver denied a "Sign in with Oxy" request. A CLOSED set — the deny
|
|
231
|
+
* endpoint is unauthenticated, so it accepts no free-form text:
|
|
232
|
+
*
|
|
233
|
+
* - `'declined'` the approver rejected a request they recognised ("Not now").
|
|
234
|
+
* - `'not_me'` the approver did not start the request ("This wasn't me").
|
|
235
|
+
* The only value that records the denial as suspicious rather
|
|
236
|
+
* than an ordinary cancel, so a UI may only offer it where the
|
|
237
|
+
* user genuinely said so.
|
|
238
|
+
*/
|
|
239
|
+
export type CommonsDenyReason = 'declined' | 'not_me';
|
|
240
|
+
/**
|
|
241
|
+
* Result of finalizing an approved, OAuth-bound "Sign in with Oxy" request.
|
|
242
|
+
*
|
|
243
|
+
* This is an authorization CODE, not a session: the caller still performs the
|
|
244
|
+
* standard PKCE token exchange (`exchangeOAuthCode`) with the `codeVerifier` it
|
|
245
|
+
* has held all along. No access token, refresh token, or device secret is ever
|
|
246
|
+
* produced by finalization.
|
|
247
|
+
*/
|
|
248
|
+
export interface CommonsOAuthFinalizeResult {
|
|
249
|
+
/** Single-use OAuth authorization code. */
|
|
250
|
+
code: string;
|
|
251
|
+
/** The exact registered redirect URI the request was bound to. */
|
|
252
|
+
redirectUri: string;
|
|
253
|
+
/** Lifetime of the authorization code, in seconds. */
|
|
254
|
+
expiresIn: number;
|
|
255
|
+
}
|
|
97
256
|
export interface ServiceTokenResponse {
|
|
98
257
|
token: string;
|
|
99
258
|
expiresIn: number;
|
|
@@ -372,33 +531,120 @@ export declare function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(B
|
|
|
372
531
|
* returns the server-issued public `authorizeCode` + ready-to-render
|
|
373
532
|
* `qrPayload`. Render the QR (web) / open the deep-link (same-device); the
|
|
374
533
|
* approver resolves the code and authorizes. Then poll with
|
|
375
|
-
* {@link pollCommonsSignIn} and
|
|
376
|
-
*
|
|
534
|
+
* {@link pollCommonsSignIn} and finalize.
|
|
535
|
+
*
|
|
536
|
+
* ONE request serves every delivery surface, and how it finalizes is decided
|
|
537
|
+
* here by whether an OAuth binding is attached:
|
|
538
|
+
* - no `oauth` (the default): a `device_sign_in` request — on `authorized`,
|
|
539
|
+
* exchange the `sessionToken` via the existing `claimSessionByToken`.
|
|
540
|
+
* - with `oauth`: an `oauth_authorization` request — on `authorized`, call
|
|
541
|
+
* {@link finalizeCommonsOAuth} with the same `sessionToken` to mint the
|
|
542
|
+
* single-use authorization code, then exchange it with PKCE.
|
|
377
543
|
*
|
|
378
544
|
* @param params.clientId - The RP's registered OAuth client id
|
|
379
545
|
* (ApplicationCredential publicKey); required so the server can resolve the
|
|
380
546
|
* requesting application's identity.
|
|
547
|
+
* @param params.oauth - Optional OAuth binding ({@link CommonsOAuthContext}).
|
|
548
|
+
* Carries only the redirect URI, the PKCE S256 challenge, the requested
|
|
549
|
+
* scope, and an optional delegated `subjectAccountId` — never the PKCE
|
|
550
|
+
* verifier, the OAuth `state`, or any token.
|
|
381
551
|
*/
|
|
382
552
|
startCommonsSignIn(params: {
|
|
383
553
|
clientId: string;
|
|
554
|
+
oauth?: CommonsOAuthContext;
|
|
384
555
|
}): Promise<CommonsSignInHandle>;
|
|
385
556
|
/**
|
|
386
557
|
* MECHANISM B (relying party) — poll a device-flow session for approval.
|
|
387
558
|
*
|
|
388
559
|
* Backstop for the auth socket. On `authorized` (with a `sessionId`), the
|
|
389
|
-
* caller
|
|
390
|
-
*
|
|
560
|
+
* caller finalizes: `claimSessionByToken` for a `device_sign_in` request,
|
|
561
|
+
* {@link finalizeCommonsOAuth} for an `oauth_authorization` one.
|
|
562
|
+
*
|
|
563
|
+
* Every field is narrowed fail-safe. `authorized` counts only as a literal
|
|
564
|
+
* `true`, the identifiers only as non-empty strings, and the delivery
|
|
565
|
+
* progress timestamps degrade to `null` when absent or unparseable — so a
|
|
566
|
+
* partial or older-API payload can advance the waiting UI at most, never
|
|
567
|
+
* make it believe a request was approved.
|
|
391
568
|
*
|
|
392
569
|
* @param sessionToken - The secret token from {@link startCommonsSignIn}.
|
|
393
570
|
*/
|
|
394
571
|
pollCommonsSignIn(sessionToken: string): Promise<CommonsSignInStatus>;
|
|
572
|
+
/**
|
|
573
|
+
* MECHANISM B (relying party) — ask Oxy to DELIVER a pending sign-in request
|
|
574
|
+
* to the identity's known Commons installations.
|
|
575
|
+
*
|
|
576
|
+
* This is the automatic half of "one intention, one primary action": rather
|
|
577
|
+
* than offering the user a menu of transports, the caller asks for delivery
|
|
578
|
+
* and lets the answer pick the route. Pass the returned `targets` to
|
|
579
|
+
* `selectCommonsDelivery` (`utils/commonsDelivery`) — `targets: 0` means no
|
|
580
|
+
* capable Commons installation is registered, which is a NORMAL outcome that
|
|
581
|
+
* resolves to the QR route, not an error to surface.
|
|
582
|
+
*
|
|
583
|
+
* **Requires a bearer.** Delivery is only allowed when Oxy already knows the
|
|
584
|
+
* intended identity from a trusted authenticated context — a request that
|
|
585
|
+
* merely carries a username or email typed into an unauthenticated browser
|
|
586
|
+
* must never be able to ring somebody's phone.
|
|
587
|
+
*
|
|
588
|
+
* The push it sends carries only `{ type, approvalUrl }` where the URL holds
|
|
589
|
+
* the public `authorizeCode` — no display data, no secrets. Commons resolves
|
|
590
|
+
* everything it shows from `getCommonsApprovalInfo`.
|
|
591
|
+
*
|
|
592
|
+
* @param authorizeCode - The public code from {@link startCommonsSignIn}.
|
|
593
|
+
*/
|
|
594
|
+
deliverCommonsSignIn(authorizeCode: string): Promise<CommonsDeliveryResult>;
|
|
595
|
+
/**
|
|
596
|
+
* MECHANISM B (approver / Commons) — report that the approval route was
|
|
597
|
+
* OPENED, so the waiting relying party can show "Opened in Commons".
|
|
598
|
+
*
|
|
599
|
+
* Progress only. It is idempotent, applies to a `pending` request alone, and
|
|
600
|
+
* records a timestamp (`openedAt`) — it never approves, authorizes, or
|
|
601
|
+
* advances the authorization state machine. Public, like the other approver
|
|
602
|
+
* handles: the approver has only the public `authorizeCode` at this point
|
|
603
|
+
* and has not yet signed anything.
|
|
604
|
+
*
|
|
605
|
+
* Best-effort by nature — a failure here costs the user only a progress
|
|
606
|
+
* line, so callers are free to ignore a rejection and continue to the
|
|
607
|
+
* approval screen.
|
|
608
|
+
*
|
|
609
|
+
* @param authorizeCode - The public code scanned from the QR / deep-link / push.
|
|
610
|
+
*/
|
|
611
|
+
markCommonsApprovalOpened(authorizeCode: string): Promise<void>;
|
|
612
|
+
/**
|
|
613
|
+
* MECHANISM B (relying party) — finalize an APPROVED, OAuth-bound request
|
|
614
|
+
* into a single-use OAuth authorization code.
|
|
615
|
+
*
|
|
616
|
+
* The OAuth counterpart of `claimSessionByToken`: same secret credential,
|
|
617
|
+
* same single-use semantics, different output. Call it once the request the
|
|
618
|
+
* RP started with an `oauth` binding reports `authorized`; the server
|
|
619
|
+
* atomically mints exactly ONE `AuthCode` bound to the redirect URI, PKCE
|
|
620
|
+
* challenge, scopes, approving identity, and any delegated subject account
|
|
621
|
+
* the request was created with. A second call cannot mint another code.
|
|
622
|
+
*
|
|
623
|
+
* The result is an authorization CODE, never a token — the caller completes
|
|
624
|
+
* the flow with the ordinary PKCE exchange (`exchangeOAuthCode`) using the
|
|
625
|
+
* `codeVerifier` it never sent anywhere. Nothing here is exposed to the
|
|
626
|
+
* popup: the code travels back through the registered callback, and the
|
|
627
|
+
* main window owns the verifier.
|
|
628
|
+
*
|
|
629
|
+
* Like `claimSessionByToken`, this needs no Authorization header — the
|
|
630
|
+
* high-entropy SECRET `sessionToken` IS the credential. Never pass the
|
|
631
|
+
* public `authorizeCode` here; it is the approver's handle, not the
|
|
632
|
+
* initiator's. Every server-side failure (wrong/expired/already-finalized
|
|
633
|
+
* request, non-OAuth purpose, missing permission for the delegated account)
|
|
634
|
+
* surfaces as one generic error, so nothing about the request's state can be
|
|
635
|
+
* probed from outside.
|
|
636
|
+
*
|
|
637
|
+
* @param sessionToken - The secret token from {@link startCommonsSignIn}.
|
|
638
|
+
*/
|
|
639
|
+
finalizeCommonsOAuth(sessionToken: string): Promise<CommonsOAuthFinalizeResult>;
|
|
395
640
|
/**
|
|
396
641
|
* MECHANISM B (approver / Commons) — resolve the TRUSTED identity of a
|
|
397
642
|
* sign-in request from its public `authorizeCode`.
|
|
398
643
|
*
|
|
399
|
-
* The returned `application`
|
|
400
|
-
*
|
|
401
|
-
* strings carried in the QR payload. Public (no auth
|
|
644
|
+
* The returned `application` and `subjectAccount` are resolved server-side
|
|
645
|
+
* and are the only safe things to display in the approval UI — NEVER trust
|
|
646
|
+
* the app/name/origin strings carried in the QR payload. Public (no auth
|
|
647
|
+
* required).
|
|
402
648
|
*
|
|
403
649
|
* @param authorizeCode - The public code scanned from the QR / deep-link.
|
|
404
650
|
*/
|
|
@@ -426,8 +672,13 @@ export declare function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(B
|
|
|
426
672
|
* device-flow session so the RP stops waiting.
|
|
427
673
|
*
|
|
428
674
|
* @param authorizeCode - The public code being denied.
|
|
675
|
+
* @param reason - Optional closed-set reason ({@link CommonsDenyReason}).
|
|
676
|
+
* Pass `'not_me'` ONLY when the user actually reported the request as one
|
|
677
|
+
* they did not start — the server records it as a suspicious denial rather
|
|
678
|
+
* than an ordinary cancel. Omitting it sends the exact body this endpoint
|
|
679
|
+
* has always received.
|
|
429
680
|
*/
|
|
430
|
-
denyCommonsSignIn(authorizeCode: string): Promise<CommonsSignInActionResult>;
|
|
681
|
+
denyCommonsSignIn(authorizeCode: string, reason?: CommonsDenyReason): Promise<CommonsSignInActionResult>;
|
|
431
682
|
/**
|
|
432
683
|
* Internal: decode (without verifying) the `sessionId` claim from a
|
|
433
684
|
* server-signed access token. The server already verified the signature;
|
|
@@ -15,6 +15,24 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { type DeviceTokenMintResponse, type DeviceHubTicketIssueResponse, type DeviceHubTicketRedeemResponse } from '@oxyhq/contracts';
|
|
17
17
|
import type { OxyServicesBase } from '../OxyServices.base';
|
|
18
|
+
/**
|
|
19
|
+
* The server's `401 account_not_on_device` for a PINNED mint: the requested
|
|
20
|
+
* `accountId` is not (or is no longer) a live account of this device session.
|
|
21
|
+
*
|
|
22
|
+
* Distinguished from every other mint 401 because the remedy is different: the
|
|
23
|
+
* device secret is FINE — it is the identity binding that went stale (the
|
|
24
|
+
* account was signed out on this device, or revoked). An identity-bound caller
|
|
25
|
+
* must re-establish its session from the local key rather than drop/clear the
|
|
26
|
+
* device credential.
|
|
27
|
+
*/
|
|
28
|
+
export declare class AccountNotOnDeviceError extends Error {
|
|
29
|
+
readonly accountId: string;
|
|
30
|
+
readonly cause?: unknown | undefined;
|
|
31
|
+
readonly name = "AccountNotOnDeviceError";
|
|
32
|
+
/** HTTP status of the originating response; mirrors the ApiError shape. */
|
|
33
|
+
readonly status = 401;
|
|
34
|
+
constructor(accountId: string, cause?: unknown | undefined);
|
|
35
|
+
}
|
|
18
36
|
export declare function OxyServicesDeviceBootMixin<T extends typeof OxyServicesBase>(Base: T): {
|
|
19
37
|
new (...args: any[]): {
|
|
20
38
|
/**
|
|
@@ -38,9 +56,21 @@ export declare function OxyServicesDeviceBootMixin<T extends typeof OxyServicesB
|
|
|
38
56
|
* boot's worst-case time-to-route. A transient failure surfaces once and the
|
|
39
57
|
* scheduler/401 path retries it later.
|
|
40
58
|
*
|
|
59
|
+
* `options.accountId` PINS the mint to one account of the device instead of
|
|
60
|
+
* whichever account is currently active. It exists for identity-bound
|
|
61
|
+
* clients (Commons), whose authenticated user is fixed by a local
|
|
62
|
+
* cryptographic key and must never follow an account switch made by another
|
|
63
|
+
* app on the same device. The server never mutates `activeAccountId` for a
|
|
64
|
+
* pinned mint — the returned `state` still reports the device's true active
|
|
65
|
+
* account — and rejects a non-member/dead account with
|
|
66
|
+
* `401 account_not_on_device`, surfaced here as {@link AccountNotOnDeviceError}.
|
|
67
|
+
*
|
|
68
|
+
* @throws {AccountNotOnDeviceError} when a pinned mint's account is not on the device.
|
|
41
69
|
* @throws if the response does not match {@link deviceTokenMintResponseSchema}.
|
|
42
70
|
*/
|
|
43
|
-
mintFromDeviceSecret(deviceId: string, deviceSecret: string
|
|
71
|
+
mintFromDeviceSecret(deviceId: string, deviceSecret: string, options?: {
|
|
72
|
+
accountId?: string;
|
|
73
|
+
}): Promise<DeviceTokenMintResponse>;
|
|
44
74
|
/** Mint a one-time hub sync ticket (bearer required). */
|
|
45
75
|
issueHubTicket(returnOrigin: string): Promise<DeviceHubTicketIssueResponse>;
|
|
46
76
|
/** Redeem a hub sync ticket for a fresh device secret (public). */
|