@tempoxyz/auth 0.0.0-pr-6.sha-b989a0e → 0.0.0-pr-7.sha-59fc900
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 +16 -19
- package/dist/Actions.d.ts +15 -15
- package/dist/Actions.js +8 -8
- package/dist/Auth.d.ts +7 -7
- package/dist/Auth.js +1 -1
- package/dist/Key.d.ts +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @tempoxyz/auth
|
|
2
2
|
|
|
3
|
-
Sign
|
|
3
|
+
Sign users in to Tempo through Tempo Auth, and get back their tokens for Tempo APIs and a [viem](https://viem.sh) access key account on their Tempo Account.
|
|
4
4
|
|
|
5
5
|
Every sign-in returns the same `Authorization`. Send transactions with its `account` through viem, and call Tempo APIs with its `tokens.accessToken`.
|
|
6
6
|
|
|
@@ -41,18 +41,15 @@ await client.token.transferSync({
|
|
|
41
41
|
pnpm add @tempoxyz/auth viem
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
viem is a peer dependency.
|
|
45
|
-
|
|
46
44
|
## Before you start
|
|
47
45
|
|
|
48
|
-
- **Register the app.**
|
|
49
|
-
- **Allow the app's origin.** Apps that call Tempo Auth from their own page need their origin in Tempo Auth's `INTERNAL_ORIGINS`.
|
|
46
|
+
- **Register the app.** Add it to Tempo Auth's `apps.config.ts`, with every redirect URI it uses, and mark it `headless` if it calls Tempo Auth from its own page. Merging creates its WorkOS Connect app, whose `client_id` is the `clientId` you pass to `Auth.create`. An app with a backend also needs a client secret from the WorkOS dashboard.
|
|
50
47
|
|
|
51
|
-
The CLI device grant needs
|
|
48
|
+
The CLI device grant needs no registration. It signs in as Tempo Auth's own `tempo-cli` app.
|
|
52
49
|
|
|
53
50
|
## Access keys
|
|
54
51
|
|
|
55
|
-
Each sign-in creates a key for the app and asks Tempo Auth to authorize it on the
|
|
52
|
+
Each sign-in creates a key for the app and asks Tempo Auth to authorize it on the user's Tempo Account. The `accessKey` option says what the key may do, with viem's `Expiry` and `Scopes` helpers:
|
|
56
53
|
|
|
57
54
|
| Field | Meaning |
|
|
58
55
|
| --------- | ----------------------------------------------------------------------------- |
|
|
@@ -61,7 +58,7 @@ Each sign-in creates a key for the app and asks Tempo Auth to authorize it on th
|
|
|
61
58
|
| `limits` | One-time spending limits per token, such as `[{ limit: 10_000_000n, token }]` |
|
|
62
59
|
| `scopes` | The calls the key may make, such as `[Scopes.tip20(token).transfer()]` |
|
|
63
60
|
|
|
64
|
-
Flows without a Tempo Auth page (`authorize`, `verifyCode`) must stay within Tempo Auth's ceiling, about $1,000 per token. Flows with a page (`redirect`, `createAuthorizationUrl`, `authorizeDevice`) show the limits to the
|
|
61
|
+
Flows without a Tempo Auth page (`authorize`, `verifyCode`) must stay within Tempo Auth's ceiling, about $1,000 per token. Flows with a page (`redirect`, `createAuthorizationUrl`, `authorizeDevice`) show the limits to the user, who approves them, so they may go beyond it.
|
|
65
62
|
|
|
66
63
|
The returned `account` attaches the key's authorization to its first transaction, which registers the key on chain.
|
|
67
64
|
|
|
@@ -69,10 +66,10 @@ The returned `account` attaches the key's authorization to its first transaction
|
|
|
69
66
|
|
|
70
67
|
### Your own sign-in UI
|
|
71
68
|
|
|
72
|
-
For a browser app that renders its own email form. The page calls Tempo Auth with the
|
|
69
|
+
For a browser app that renders its own email form. The page calls Tempo Auth with the user's Tempo Auth session, so it works across every app on the same site.
|
|
73
70
|
|
|
74
71
|
```ts
|
|
75
|
-
// A
|
|
72
|
+
// A user already signed in to Tempo Auth, from any app, needs no form.
|
|
76
73
|
const authorization = await Actions.authorize(auth, { accessKey })
|
|
77
74
|
|
|
78
75
|
// Otherwise, sign in with an emailed code.
|
|
@@ -126,7 +123,7 @@ const authorization = await Actions.handleCallback(auth, {
|
|
|
126
123
|
|
|
127
124
|
### A CLI
|
|
128
125
|
|
|
129
|
-
For a command-line tool. The
|
|
126
|
+
For a command-line tool. The user approves a code in any browser, and the CLI waits.
|
|
130
127
|
|
|
131
128
|
```ts
|
|
132
129
|
const device = await Actions.authorizeDevice(auth, {
|
|
@@ -187,7 +184,7 @@ try {
|
|
|
187
184
|
|
|
188
185
|
| Action | Returns |
|
|
189
186
|
| ---------------------------------------------------------- | -------------------------------------------------------------------------- |
|
|
190
|
-
| `authorize(auth, { accessKey })` | An `Authorization` for a
|
|
187
|
+
| `authorize(auth, { accessKey })` | An `Authorization` for a user already signed in, or `undefined` |
|
|
191
188
|
| `authorizeDevice(auth, { accessKey, device })` | The code to show and a `wait()` that resolves with an `Authorization` |
|
|
192
189
|
| `createAuthorizationUrl(auth, { accessKey, redirectUri })` | The `url` to send the browser to, and the `pending` state to keep |
|
|
193
190
|
| `getProviders(auth)` | The OAuth providers Tempo Auth offers, as `{ id, name }` |
|
|
@@ -197,17 +194,17 @@ try {
|
|
|
197
194
|
| `refresh(auth, { refreshToken })` | New `Tokens` |
|
|
198
195
|
| `sendCode(auth, { email })` | Nothing. Tempo Auth emails a code |
|
|
199
196
|
| `signIn(auth, { provider } \| { url })` | Nothing. The browser leaves for the provider or SSO connection |
|
|
200
|
-
| `signOut(auth)` | Nothing. The
|
|
197
|
+
| `signOut(auth)` | Nothing. The user's Tempo Auth session ends |
|
|
201
198
|
| `verifyCode(auth, { accessKey, code, email })` | An `Authorization`, or the `step` the address requires first |
|
|
202
199
|
|
|
203
200
|
### `Authorization`
|
|
204
201
|
|
|
205
|
-
| Field | Meaning
|
|
206
|
-
| --------- |
|
|
207
|
-
| `account` | The app's key as a viem access key account, acting for the
|
|
208
|
-
| `key` | The same key as JSON, for `Key.toAccount`
|
|
209
|
-
| `tokens` | `accessToken`, `expiresAt`, and the optional `idToken` and `refreshToken`
|
|
210
|
-
| `user` | The
|
|
202
|
+
| Field | Meaning |
|
|
203
|
+
| --------- | ------------------------------------------------------------------------------- |
|
|
204
|
+
| `account` | The app's key as a viem access key account, acting for the user's Tempo Account |
|
|
205
|
+
| `key` | The same key as JSON, for `Key.toAccount` |
|
|
206
|
+
| `tokens` | `accessToken`, `expiresAt`, and the optional `idToken` and `refreshToken` |
|
|
207
|
+
| `user` | The user's `email` and `id`, the `sub` of every token |
|
|
211
208
|
|
|
212
209
|
### `Key`
|
|
213
210
|
|
package/dist/Actions.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type AccessKey, type Auth, type Authorization, type Pending, type Provider, type Step, type Tokens } from './Auth.ts';
|
|
2
2
|
/**
|
|
3
|
-
* Authorizes the app for a
|
|
3
|
+
* Authorizes the app for a user already signed in to Tempo Auth, from any app. Returns
|
|
4
4
|
* `undefined` without a session, so the app shows sign-in. The key must fit Tempo Auth's headless
|
|
5
5
|
* ceiling.
|
|
6
6
|
*
|
|
@@ -20,7 +20,7 @@ export declare namespace authorize {
|
|
|
20
20
|
type ReturnType = Authorization | undefined;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
* Starts the device grant for a CLI: the
|
|
23
|
+
* Starts the device grant for a CLI: the user approves `userCode` at `verificationUri` from any
|
|
24
24
|
* browser, and `wait` resolves once they do.
|
|
25
25
|
*
|
|
26
26
|
* @example
|
|
@@ -41,18 +41,18 @@ export declare namespace authorizeDevice {
|
|
|
41
41
|
type ReturnType = {
|
|
42
42
|
/** Seconds until the code expires. */
|
|
43
43
|
expiresIn: number;
|
|
44
|
-
/** The code the
|
|
44
|
+
/** The code the user confirms in the browser. */
|
|
45
45
|
userCode: string;
|
|
46
|
-
/** Where the
|
|
46
|
+
/** Where the user enters the code. */
|
|
47
47
|
verificationUri: string;
|
|
48
|
-
/** Where the
|
|
48
|
+
/** Where the user approves the code, with it already filled in. */
|
|
49
49
|
verificationUriComplete: string;
|
|
50
|
-
/** Resolves with the authorization once the
|
|
50
|
+
/** Resolves with the authorization once the user approves. */
|
|
51
51
|
wait: () => Promise<Authorization>;
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
54
|
/**
|
|
55
|
-
* Returns the URL that signs the
|
|
55
|
+
* Returns the URL that signs the user in on Tempo Auth's pages and redirects back with a code
|
|
56
56
|
* and the key authorization, and the {@link Pending} state to keep until then, such as in a
|
|
57
57
|
* sealed cookie. {@link handleCallback} finishes it.
|
|
58
58
|
*
|
|
@@ -69,7 +69,7 @@ export declare namespace authorizeDevice {
|
|
|
69
69
|
export declare function createAuthorizationUrl(auth: Auth, options: createAuthorizationUrl.Options): Promise<createAuthorizationUrl.ReturnType>;
|
|
70
70
|
export declare namespace createAuthorizationUrl {
|
|
71
71
|
type Options = {
|
|
72
|
-
/** What the app's key may do. Tempo Auth's pages show it, and the
|
|
72
|
+
/** What the app's key may do. Tempo Auth's pages show it, and the user approves it. */
|
|
73
73
|
accessKey: AccessKey;
|
|
74
74
|
/** Where Tempo Auth redirects back to. Defaults to the instance's `redirectUri`. */
|
|
75
75
|
redirectUri?: string | undefined;
|
|
@@ -147,7 +147,7 @@ export declare namespace handleRedirect {
|
|
|
147
147
|
export declare function redirect(auth: Auth, options: redirect.Options): Promise<void>;
|
|
148
148
|
export declare namespace redirect {
|
|
149
149
|
type Options = {
|
|
150
|
-
/** What the app's key may do. Tempo Auth's pages show it, and the
|
|
150
|
+
/** What the app's key may do. Tempo Auth's pages show it, and the user approves it. */
|
|
151
151
|
accessKey: AccessKey;
|
|
152
152
|
};
|
|
153
153
|
}
|
|
@@ -169,17 +169,17 @@ export declare namespace refresh {
|
|
|
169
169
|
};
|
|
170
170
|
}
|
|
171
171
|
/**
|
|
172
|
-
* Emails the
|
|
172
|
+
* Emails the user a sign-in code. The response is the same for every address.
|
|
173
173
|
*
|
|
174
174
|
* @example
|
|
175
175
|
* ```ts
|
|
176
|
-
* await Actions.sendCode(auth, { email: '
|
|
176
|
+
* await Actions.sendCode(auth, { email: 'user@example.com' })
|
|
177
177
|
* ```
|
|
178
178
|
*/
|
|
179
179
|
export declare function sendCode(auth: Auth, options: sendCode.Options): Promise<void>;
|
|
180
180
|
export declare namespace sendCode {
|
|
181
181
|
type Options = {
|
|
182
|
-
/** The
|
|
182
|
+
/** The user's email address. */
|
|
183
183
|
email: string;
|
|
184
184
|
};
|
|
185
185
|
}
|
|
@@ -206,7 +206,7 @@ export declare namespace signIn {
|
|
|
206
206
|
};
|
|
207
207
|
}
|
|
208
208
|
/**
|
|
209
|
-
* Ends the
|
|
209
|
+
* Ends the user's Tempo Auth session, which signs them out of every app that relies on it.
|
|
210
210
|
*
|
|
211
211
|
* @example
|
|
212
212
|
* ```ts
|
|
@@ -215,7 +215,7 @@ export declare namespace signIn {
|
|
|
215
215
|
*/
|
|
216
216
|
export declare function signOut(auth: Auth): Promise<void>;
|
|
217
217
|
/**
|
|
218
|
-
* Signs the
|
|
218
|
+
* Signs the user in with the code they were emailed, and authorizes the app in the same call.
|
|
219
219
|
* Returns a {@link Step} when the address requires SSO, which {@link signIn} continues.
|
|
220
220
|
*
|
|
221
221
|
* @example
|
|
@@ -229,7 +229,7 @@ export declare namespace verifyCode {
|
|
|
229
229
|
type Options = {
|
|
230
230
|
/** What the app's key may do. It must fit the headless ceiling. */
|
|
231
231
|
accessKey: AccessKey;
|
|
232
|
-
/** The 6-digit code the
|
|
232
|
+
/** The 6-digit code the user was emailed. */
|
|
233
233
|
code: string;
|
|
234
234
|
/** The address the code was sent to. */
|
|
235
235
|
email: string;
|
package/dist/Actions.js
CHANGED
|
@@ -8,7 +8,7 @@ import { RequestError, } from './Auth.js';
|
|
|
8
8
|
import * as Key from './Key.js';
|
|
9
9
|
import { request } from './internal/request.js';
|
|
10
10
|
/**
|
|
11
|
-
* Authorizes the app for a
|
|
11
|
+
* Authorizes the app for a user already signed in to Tempo Auth, from any app. Returns
|
|
12
12
|
* `undefined` without a session, so the app shows sign-in. The key must fit Tempo Auth's headless
|
|
13
13
|
* ceiling.
|
|
14
14
|
*
|
|
@@ -34,7 +34,7 @@ export async function authorize(auth, options) {
|
|
|
34
34
|
return authorization(await json(response), { privateKey });
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
|
-
* Starts the device grant for a CLI: the
|
|
37
|
+
* Starts the device grant for a CLI: the user approves `userCode` at `verificationUri` from any
|
|
38
38
|
* browser, and `wait` resolves once they do.
|
|
39
39
|
*
|
|
40
40
|
* @example
|
|
@@ -53,7 +53,7 @@ export async function authorizeDevice(auth, options) {
|
|
|
53
53
|
.keyAuthorization,
|
|
54
54
|
},
|
|
55
55
|
}));
|
|
56
|
-
/** Polls until the
|
|
56
|
+
/** Polls until the user approves or denies the code, or it expires. */
|
|
57
57
|
async function wait() {
|
|
58
58
|
let interval = code.interval;
|
|
59
59
|
const deadline = Date.now() + code.expires_in * 1000;
|
|
@@ -89,7 +89,7 @@ export async function authorizeDevice(auth, options) {
|
|
|
89
89
|
};
|
|
90
90
|
}
|
|
91
91
|
/**
|
|
92
|
-
* Returns the URL that signs the
|
|
92
|
+
* Returns the URL that signs the user in on Tempo Auth's pages and redirects back with a code
|
|
93
93
|
* and the key authorization, and the {@link Pending} state to keep until then, such as in a
|
|
94
94
|
* sealed cookie. {@link handleCallback} finishes it.
|
|
95
95
|
*
|
|
@@ -233,11 +233,11 @@ export function refresh(auth, options) {
|
|
|
233
233
|
});
|
|
234
234
|
}
|
|
235
235
|
/**
|
|
236
|
-
* Emails the
|
|
236
|
+
* Emails the user a sign-in code. The response is the same for every address.
|
|
237
237
|
*
|
|
238
238
|
* @example
|
|
239
239
|
* ```ts
|
|
240
|
-
* await Actions.sendCode(auth, { email: '
|
|
240
|
+
* await Actions.sendCode(auth, { email: 'user@example.com' })
|
|
241
241
|
* ```
|
|
242
242
|
*/
|
|
243
243
|
export async function sendCode(auth, options) {
|
|
@@ -260,7 +260,7 @@ export function signIn(auth, options) {
|
|
|
260
260
|
window.location.assign(url);
|
|
261
261
|
}
|
|
262
262
|
/**
|
|
263
|
-
* Ends the
|
|
263
|
+
* Ends the user's Tempo Auth session, which signs them out of every app that relies on it.
|
|
264
264
|
*
|
|
265
265
|
* @example
|
|
266
266
|
* ```ts
|
|
@@ -272,7 +272,7 @@ export async function signOut(auth) {
|
|
|
272
272
|
await json(await post(auth, '/api/auth/logout', { json: {} }));
|
|
273
273
|
}
|
|
274
274
|
/**
|
|
275
|
-
* Signs the
|
|
275
|
+
* Signs the user in with the code they were emailed, and authorizes the app in the same call.
|
|
276
276
|
* Returns a {@link Step} when the address requires SSO, which {@link signIn} continues.
|
|
277
277
|
*
|
|
278
278
|
* @example
|
package/dist/Auth.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A Tempo Auth instance, and the types its actions take and return. Create one with
|
|
3
3
|
* {@link create}, then pass it to each action in `Actions`. Every sign-in returns an
|
|
4
|
-
* {@link Authorization}: the
|
|
4
|
+
* {@link Authorization}: the user's tokens, and a viem access key account.
|
|
5
5
|
*
|
|
6
6
|
* @example
|
|
7
7
|
* ```ts
|
|
@@ -51,13 +51,13 @@ export type AccessKey = Pick<KeyAuthorization.KeyAuthorization, 'limits' | 'scop
|
|
|
51
51
|
};
|
|
52
52
|
/** What every sign-in returns. */
|
|
53
53
|
export type Authorization = {
|
|
54
|
-
/** The app's access key, as a viem account acting for the
|
|
54
|
+
/** The app's access key, as a viem account acting for the user's Tempo Account. */
|
|
55
55
|
account: ReturnType<typeof Key.toAccount>;
|
|
56
56
|
/** The same key as JSON, for apps that store it and rebuild it with `Key.toAccount`. */
|
|
57
57
|
key: Key.Key;
|
|
58
58
|
/** The app's tokens for Tempo APIs. */
|
|
59
59
|
tokens: Tokens;
|
|
60
|
-
/** The signed-in
|
|
60
|
+
/** The signed-in user, from the ID token. */
|
|
61
61
|
user: User;
|
|
62
62
|
};
|
|
63
63
|
/** The app's tokens for Tempo APIs. */
|
|
@@ -66,16 +66,16 @@ export type Tokens = {
|
|
|
66
66
|
accessToken: string;
|
|
67
67
|
/** When the access token expires, in milliseconds. */
|
|
68
68
|
expiresAt: number;
|
|
69
|
-
/** The OIDC ID token, which names the
|
|
69
|
+
/** The OIDC ID token, which names the user. A refresh may omit it. */
|
|
70
70
|
idToken?: string | undefined;
|
|
71
71
|
/** Exchanges for new tokens through `Actions.refresh`. It rotates on every refresh. */
|
|
72
72
|
refreshToken?: string | undefined;
|
|
73
73
|
};
|
|
74
|
-
/** The signed-in
|
|
74
|
+
/** The signed-in user. */
|
|
75
75
|
export type User = {
|
|
76
|
-
/** The
|
|
76
|
+
/** The user's verified email address. */
|
|
77
77
|
email: string;
|
|
78
|
-
/** The
|
|
78
|
+
/** The user's ID, the `sub` of every token. */
|
|
79
79
|
id: string;
|
|
80
80
|
};
|
|
81
81
|
/** An OAuth provider's short name, as `Actions.getProviders` lists them. */
|
package/dist/Auth.js
CHANGED
|
@@ -17,7 +17,7 @@ export class RequestError extends Error {
|
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
19
|
export function create(options) {
|
|
20
|
-
// Every authorization reads the
|
|
20
|
+
// Every authorization reads the user from the ID token, which needs `openid` and `email`.
|
|
21
21
|
const scopes = (options.scope ?? 'offline_access').split(' ').filter(Boolean);
|
|
22
22
|
return {
|
|
23
23
|
...options,
|
package/dist/Key.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* An app's access key on a
|
|
2
|
+
* An app's access key on a user's Tempo Account, as the app stores it: the key, the account it
|
|
3
3
|
* acts for, and the authorization Tempo Auth signed for it.
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tempoxyz/auth",
|
|
3
|
-
"version": "0.0.0-pr-
|
|
4
|
-
"description": "Signs
|
|
3
|
+
"version": "0.0.0-pr-7.sha-59fc900",
|
|
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": {
|
|
7
7
|
".": {
|