@tempoxyz/auth 0.0.0-pr-87.sha-bc40370 → 0.0.0-pr-87.sha-226d5ea

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/Actions.d.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  * every flow shares sit at the top level.
5
5
  * @module
6
6
  */
7
+ import { Authentication } from 'ox/webauthn';
7
8
  import type { Account } from 'viem/tempo';
8
9
  import type { Auth } from './Auth.ts';
9
10
  import type { Authorization } from './Authorization.ts';
@@ -20,7 +21,12 @@ export * as redirect from './actions/redirect.ts';
20
21
  /**
21
22
  * Authorizes the app for a user already signed in to Tempo Auth, from any app. Returns
22
23
  * `undefined` without a session, so the app shows sign-in. The key must fit Tempo Auth's headless
23
- * ceiling.
24
+ * ceiling. An `account` the call names becomes the app's account for its later requests, such as
25
+ * the one the user chose from a sign-in's account step.
26
+ *
27
+ * A passkey-owned account signs the key with a passkey prompt on the page, when the page is the
28
+ * app's own on Tempo's domain. Elsewhere the call throws a `RequestError` with reason
29
+ * `webauthn_required`, and `Actions.redirect.start` authorizes the key on Tempo Auth's pages.
24
30
  *
25
31
  * @example
26
32
  * ```ts
@@ -38,7 +44,8 @@ export declare namespace authorize {
38
44
  accessKey?: Account.Account | undefined;
39
45
  /**
40
46
  * The address of the user's Tempo Account the key acts for, such as the one the user chose from
41
- * a sign-in's account step. Takes the place of `accessKey`'s `access`.
47
+ * a sign-in's account step. Takes the place of `accessKey`'s `access`, and becomes the app's
48
+ * account for its later requests that name none.
42
49
  */
43
50
  account?: `0x${string}` | undefined;
44
51
  /**
@@ -47,6 +54,12 @@ export declare namespace authorize {
47
54
  * `tempo-auth:sign` scope may send one.
48
55
  */
49
56
  challenge?: string | undefined;
57
+ /**
58
+ * Runs the WebAuthn ceremony in place of `navigator.credentials.get`, for a passkey-owned
59
+ * account, such as a native passkey module. Its assertion must report a web origin on the
60
+ * relying party's domain that the app registered.
61
+ */
62
+ getFn?: Authentication.sign.Options['getFn'] | undefined;
50
63
  /** What the key may do. It must fit the headless ceiling, which fills what it leaves out. */
51
64
  permissions?: Permissions<chainId> | undefined;
52
65
  };
package/dist/Actions.js CHANGED
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Tempo Auth's actions. Each takes an instance from `Auth.create`. Each sign-in flow has its own
3
+ * namespace, `oauth` holds the standard OAuth endpoints for tokens an app holds, and the actions
4
+ * every flow shares sit at the top level.
5
+ * @module
6
+ */
7
+ import { Authentication } from 'ox/webauthn';
1
8
  import * as AccessKey from './internal/accessKey.js';
2
9
  import * as Api from './internal/api.js';
3
10
  import { request } from './internal/request.js';
@@ -12,7 +19,12 @@ export * as redirect from './actions/redirect.js';
12
19
  /**
13
20
  * Authorizes the app for a user already signed in to Tempo Auth, from any app. Returns
14
21
  * `undefined` without a session, so the app shows sign-in. The key must fit Tempo Auth's headless
15
- * ceiling.
22
+ * ceiling. An `account` the call names becomes the app's account for its later requests, such as
23
+ * the one the user chose from a sign-in's account step.
24
+ *
25
+ * A passkey-owned account signs the key with a passkey prompt on the page, when the page is the
26
+ * app's own on Tempo's domain. Elsewhere the call throws a `RequestError` with reason
27
+ * `webauthn_required`, and `Actions.redirect.start` authorizes the key on Tempo Auth's pages.
16
28
  *
17
29
  * @example
18
30
  * ```ts
@@ -28,17 +40,28 @@ export async function authorize(auth, options = {}) {
28
40
  if (!session.user)
29
41
  return undefined;
30
42
  const key = await AccessKey.resolve(options.accessKey);
31
- const response = await Api.post(auth, '/v1/authorize', {
32
- json: request(auth, {
33
- accessKey: key.accessKey,
34
- account: options.account,
35
- challenge: options.challenge,
36
- permissions: options.permissions,
37
- }),
43
+ const json = request(auth, {
44
+ accessKey: key.accessKey,
45
+ account: options.account,
46
+ challenge: options.challenge,
47
+ permissions: options.permissions,
38
48
  });
49
+ const response = await Api.post(auth, '/v1/authorize', { json });
39
50
  if (response.status === 401)
40
51
  return undefined;
41
- return Api.authorization(await Api.json(response), key);
52
+ const body = await Api.json(response);
53
+ if (!('step' in body))
54
+ return Api.authorization(body, key);
55
+ // The step's challenge is the key's digest, so the repeated request carries the signature.
56
+ const deserialized = Authentication.deserializeOptions(body.step.options);
57
+ const assertion = Authentication.serializeResponse(await Authentication.sign(
58
+ // ox reads `getFn` beside request options at runtime, which its types admit only beside a challenge.
59
+ options.getFn
60
+ ? { ...deserialized, getFn: options.getFn }
61
+ : deserialized));
62
+ return Api.authorization(await Api.json(await Api.post(auth, '/v1/authorize', {
63
+ json: { ...json, passkey: { assertion } },
64
+ })), key);
42
65
  }
43
66
  /**
44
67
  * Exchanges a refresh token for new tokens. Refresh tokens rotate, so store the new one.
@@ -73,11 +73,6 @@ export declare namespace tempoAuth {
73
73
  account: {
74
74
  /** `Actions.account.get`. */
75
75
  get: () => Promise<Actions.account.get.ReturnType>;
76
- /**
77
- * `Actions.account.select`, which empties the client's account until the app authorizes
78
- * the selected one.
79
- */
80
- select: (options: Actions.account.select.Options) => Promise<void>;
81
76
  };
82
77
  /**
83
78
  * `Actions.authorize`, which sets the client's account, or empties it when the user has no
package/dist/Decorator.js CHANGED
@@ -100,13 +100,6 @@ export function tempoAuth(options) {
100
100
  auth: {
101
101
  account: {
102
102
  get: () => Actions.account.get(auth),
103
- // The client stops signing as the previous account, which the app reauthorizes for the
104
- // selected one.
105
- async select(options) {
106
- const change = begin();
107
- await Actions.account.select(auth, options).catch(change.fail);
108
- await change.apply(undefined);
109
- },
110
103
  },
111
104
  async authorize(options = {}) {
112
105
  const change = begin();
@@ -1,13 +1,13 @@
1
1
  /**
2
- * Reads and selects the signed-in user's Tempo Account for the app, with its realm.
2
+ * Reads the signed-in user's Tempo Account for the app, with its realm.
3
3
  * @module
4
4
  */
5
5
  import type { Auth } from '../Auth.ts';
6
6
  import type { TempoAccount } from '../TempoAccount.ts';
7
7
  /**
8
- * Returns the signed-in user's Tempo Account for the app: the one they selected at sign-in, or else
9
- * their oldest in the app's realms, with its `realm`. A user with no account in the app's realms
10
- * receives one in its first.
8
+ * Returns the signed-in user's Tempo Account for the app, with its `realm`: the one selected at
9
+ * sign-in or last named in `Actions.authorize`, or else their oldest in the app's realms. A user
10
+ * with no account in the app's realms receives one in its first.
11
11
  *
12
12
  * @example
13
13
  * ```ts
@@ -20,23 +20,3 @@ export declare namespace get {
20
20
  /** The user's Tempo Account for the app. */
21
21
  type ReturnType = TempoAccount;
22
22
  }
23
- /**
24
- * Selects one of the signed-in user's Tempo Accounts as the app's, after a sign-in's account step.
25
- * The app's requests that name no account use it until sign-out or the app's next sign-in.
26
- *
27
- * @example
28
- * ```ts
29
- * const result = await Actions.email.signIn(auth, { code, email })
30
- * if ('step' in result && result.step.type === 'account') {
31
- * const [chosen] = result.step.accounts
32
- * await Actions.account.select(auth, { address: chosen!.address })
33
- * }
34
- * ```
35
- */
36
- export declare function select(auth: Auth, options: select.Options): Promise<void>;
37
- export declare namespace select {
38
- type Options = {
39
- /** The address of one of the user's accounts, as the account step lists it. */
40
- address: `0x${string}`;
41
- };
42
- }
@@ -1,8 +1,8 @@
1
1
  import * as Api from '../internal/api.js';
2
2
  /**
3
- * Returns the signed-in user's Tempo Account for the app: the one they selected at sign-in, or else
4
- * their oldest in the app's realms, with its `realm`. A user with no account in the app's realms
5
- * receives one in its first.
3
+ * Returns the signed-in user's Tempo Account for the app, with its `realm`: the one selected at
4
+ * sign-in or last named in `Actions.authorize`, or else their oldest in the app's realms. A user
5
+ * with no account in the app's realms receives one in its first.
6
6
  *
7
7
  * @example
8
8
  * ```ts
@@ -15,21 +15,3 @@ export async function get(auth) {
15
15
  // Tempo Auth lists the account the app uses first, and always lists one.
16
16
  return Api.tempoAccount(tempo[0]);
17
17
  }
18
- /**
19
- * Selects one of the signed-in user's Tempo Accounts as the app's, after a sign-in's account step.
20
- * The app's requests that name no account use it until sign-out or the app's next sign-in.
21
- *
22
- * @example
23
- * ```ts
24
- * const result = await Actions.email.signIn(auth, { code, email })
25
- * if ('step' in result && result.step.type === 'account') {
26
- * const [chosen] = result.step.accounts
27
- * await Actions.account.select(auth, { address: chosen!.address })
28
- * }
29
- * ```
30
- */
31
- export async function select(auth, options) {
32
- await Api.json(await Api.post(auth, '/v1/auth/account', {
33
- json: { account: options.address, client_id: auth.clientId },
34
- }));
35
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tempoxyz/auth",
3
- "version": "0.0.0-pr-87.sha-bc40370",
3
+ "version": "0.0.0-pr-87.sha-226d5ea",
4
4
  "description": "Signs users in to Tempo through Tempo Auth, and returns Viem access key accounts on their Tempo Accounts.",
5
5
  "type": "module",
6
6
  "exports": {