@gasboost/auth-app 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +115 -52
- package/dist/authentication.d.ts +1 -1
- package/dist/authentication.js +5 -6
- package/dist/handlers.d.ts +28 -0
- package/dist/handlers.js +22 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -88,7 +88,7 @@ session storage や repository を middleware 側で再定義する必要はあ
|
|
|
88
88
|
```ts
|
|
89
89
|
import { AppsScript } from "@gasboost/app";
|
|
90
90
|
import { AppsScriptAuth } from "@gasboost/auth";
|
|
91
|
-
import { authentication
|
|
91
|
+
import { authentication } from "@gasboost/auth-app";
|
|
92
92
|
|
|
93
93
|
const auth = new AppsScriptAuth({
|
|
94
94
|
repository,
|
|
@@ -105,7 +105,7 @@ const auth = new AppsScriptAuth({
|
|
|
105
105
|
},
|
|
106
106
|
});
|
|
107
107
|
|
|
108
|
-
const app = new AppsScript
|
|
108
|
+
const app = new AppsScript().use(authentication(auth));
|
|
109
109
|
```
|
|
110
110
|
|
|
111
111
|
`authentication()` は `AppsScriptAuth` の既存 session API を利用します。
|
|
@@ -114,7 +114,64 @@ const app = new AppsScript<AuthState>().use(authentication(auth));
|
|
|
114
114
|
const session = await auth.session.get(token);
|
|
115
115
|
```
|
|
116
116
|
|
|
117
|
-
session
|
|
117
|
+
有効な session が取得できた場合、middleware はその session を `AppsScript` state に設定します。
|
|
118
|
+
|
|
119
|
+
`@gasboost/app` v4 では `authentication()` の適用後、後続 handler の `context.state` から session が non-nullable として取得できます。
|
|
120
|
+
|
|
121
|
+
## Auth handlers
|
|
122
|
+
|
|
123
|
+
`handlers(auth)` は `AppsScriptAuth` の公開 API を `@gasboost/app` の RPC handler として登録できる形へ変換します。
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
import { AppsScript } from "@gasboost/app";
|
|
127
|
+
import { AppsScriptAuth } from "@gasboost/auth";
|
|
128
|
+
import { authentication, handlers } from "@gasboost/auth-app";
|
|
129
|
+
|
|
130
|
+
const auth = new AppsScriptAuth({
|
|
131
|
+
repository,
|
|
132
|
+
runtime,
|
|
133
|
+
session: {
|
|
134
|
+
storageType: "cache",
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const app = new AppsScript().use(authentication(auth)).calls(handlers(auth));
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
以下の RPC が公開されます。
|
|
142
|
+
|
|
143
|
+
- `signInEmail`
|
|
144
|
+
- `signInAppsScript`
|
|
145
|
+
- `signUpEmail`
|
|
146
|
+
- `signUpAppsScript`
|
|
147
|
+
- `getSession`
|
|
148
|
+
- `signOut`
|
|
149
|
+
|
|
150
|
+
Password Reset が有効な場合は、さらに以下も公開されます。
|
|
151
|
+
|
|
152
|
+
- `forgotPassword`
|
|
153
|
+
- `resetPassword`
|
|
154
|
+
|
|
155
|
+
`signIn` / `signUp` / Password Reset の input と result の型は `@gasboost/auth` の既存 API から推論されます。
|
|
156
|
+
|
|
157
|
+
`getSession` と `signOut` は、RPC の単一 object input contract に合わせて以下の形式になります。
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
client.getSession({
|
|
161
|
+
sessionId: "session-id",
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
client.signOut({
|
|
165
|
+
sessionId: "session-id",
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
`@gasboost/auth` 側の API 自体は変更されません。
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
await auth.session.get("session-id");
|
|
173
|
+
await auth.signOut.execute("session-id");
|
|
174
|
+
```
|
|
118
175
|
|
|
119
176
|
## Authenticated RPC
|
|
120
177
|
|
|
@@ -122,25 +179,19 @@ session の取得だけを目的とした別の authentication API は使用し
|
|
|
122
179
|
|
|
123
180
|
```ts
|
|
124
181
|
import { AppsScript } from "@gasboost/app";
|
|
125
|
-
import {
|
|
126
|
-
authentication,
|
|
127
|
-
type AuthenticatedInput,
|
|
128
|
-
type AuthState,
|
|
129
|
-
} from "@gasboost/auth-app";
|
|
182
|
+
import { authentication, type AuthenticatedInput } from "@gasboost/auth-app";
|
|
130
183
|
|
|
131
|
-
const app = new AppsScript
|
|
184
|
+
const app = new AppsScript()
|
|
132
185
|
.use(authentication(auth))
|
|
133
|
-
.call("getProfile", (_input: AuthenticatedInput) => {
|
|
134
|
-
const session =
|
|
135
|
-
|
|
136
|
-
if (!session) {
|
|
137
|
-
throw new Error("Unauthorized");
|
|
138
|
-
}
|
|
186
|
+
.call("getProfile", (_input: AuthenticatedInput, context) => {
|
|
187
|
+
const session = context.state.get("session");
|
|
139
188
|
|
|
140
189
|
return getProfile(session.userId);
|
|
141
190
|
});
|
|
142
191
|
```
|
|
143
192
|
|
|
193
|
+
`authentication(auth)` の通過後は session が state に存在することが型として保証されるため、`undefined` check は不要です。
|
|
194
|
+
|
|
144
195
|
クライアント側では token が必須になります。
|
|
145
196
|
|
|
146
197
|
```ts
|
|
@@ -149,23 +200,18 @@ client.getProfile({
|
|
|
149
200
|
});
|
|
150
201
|
```
|
|
151
202
|
|
|
152
|
-
token を渡さない呼び出しは RPC contract 上エラーになります。
|
|
153
|
-
|
|
154
203
|
追加 input が必要な場合:
|
|
155
204
|
|
|
156
205
|
```ts
|
|
157
|
-
const app = new AppsScript
|
|
206
|
+
const app = new AppsScript().use(authentication(auth)).call(
|
|
158
207
|
"updateProfile",
|
|
159
208
|
(
|
|
160
209
|
input: AuthenticatedInput<{
|
|
161
210
|
name: string;
|
|
162
211
|
}>,
|
|
212
|
+
context,
|
|
163
213
|
) => {
|
|
164
|
-
const session =
|
|
165
|
-
|
|
166
|
-
if (!session) {
|
|
167
|
-
throw new Error("Unauthorized");
|
|
168
|
-
}
|
|
214
|
+
const session = context.state.get("session");
|
|
169
215
|
|
|
170
216
|
return updateProfile({
|
|
171
217
|
userId: session.userId,
|
|
@@ -191,7 +237,7 @@ middleware はすべての RPC に認証を要求するわけではありませ
|
|
|
191
237
|
token を持たない RPC input はそのまま後続 handler へ流れます。
|
|
192
238
|
|
|
193
239
|
```ts
|
|
194
|
-
const app = new AppsScript
|
|
240
|
+
const app = new AppsScript()
|
|
195
241
|
.use(authentication(auth))
|
|
196
242
|
.call("signIn", (input: { email: string; password: string }) => {
|
|
197
243
|
return auth.signIn.email(input);
|
|
@@ -210,13 +256,11 @@ client.signIn({
|
|
|
210
256
|
input 自体を持たない公開 RPC も利用できます。
|
|
211
257
|
|
|
212
258
|
```ts
|
|
213
|
-
const app = new AppsScript
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
};
|
|
219
|
-
});
|
|
259
|
+
const app = new AppsScript().use(authentication(auth)).call("health", () => {
|
|
260
|
+
return {
|
|
261
|
+
ok: true,
|
|
262
|
+
};
|
|
263
|
+
});
|
|
220
264
|
```
|
|
221
265
|
|
|
222
266
|
## Session state
|
|
@@ -227,31 +271,36 @@ const app = new AppsScript<AuthState>()
|
|
|
227
271
|
context.state.set("session", session);
|
|
228
272
|
```
|
|
229
273
|
|
|
230
|
-
application handler
|
|
274
|
+
`authentication(auth)` より後の application handler では、`context.state` から取得できます。
|
|
231
275
|
|
|
232
276
|
```ts
|
|
233
|
-
const
|
|
277
|
+
const app = new AppsScript()
|
|
278
|
+
.use(authentication(auth))
|
|
279
|
+
.call("getProfile", (_input: AuthenticatedInput, context) => {
|
|
280
|
+
const session = context.state.get("session");
|
|
234
281
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
282
|
+
session.id;
|
|
283
|
+
session.userId;
|
|
284
|
+
session.createdAt;
|
|
285
|
+
session.expiresAt;
|
|
238
286
|
|
|
239
|
-
session.
|
|
240
|
-
|
|
241
|
-
session.createdAt;
|
|
242
|
-
session.expiresAt;
|
|
287
|
+
return getProfile(session.userId);
|
|
288
|
+
});
|
|
243
289
|
```
|
|
244
290
|
|
|
291
|
+
`authentication(auth)` が session state を保証するため、後続 handler では `session` は `undefined` になりません。
|
|
292
|
+
|
|
245
293
|
application user が必要な場合は `session.userId` を利用して application 側で取得します。
|
|
246
294
|
|
|
247
295
|
```ts
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
296
|
+
const app = new AppsScript()
|
|
297
|
+
.use(authentication(auth))
|
|
298
|
+
.call("getProfile", async (_input: AuthenticatedInput, context) => {
|
|
299
|
+
const session = context.state.get("session");
|
|
300
|
+
const user = await userRepository.find(session.userId);
|
|
253
301
|
|
|
254
|
-
|
|
302
|
+
return user;
|
|
303
|
+
});
|
|
255
304
|
```
|
|
256
305
|
|
|
257
306
|
`@gasboost/auth-app` は application User の取得までは担当しません。
|
|
@@ -298,18 +347,32 @@ Apps Script Active User を application session の代替として扱いませ
|
|
|
298
347
|
|
|
299
348
|
## Custom state
|
|
300
349
|
|
|
301
|
-
|
|
350
|
+
## Custom state
|
|
351
|
+
|
|
352
|
+
`@gasboost/app` v4 では middleware が追加する state は `.use()` によって型へ反映されます。
|
|
302
353
|
|
|
303
354
|
```ts
|
|
304
|
-
|
|
355
|
+
const app = new AppsScript().use(authentication(auth));
|
|
356
|
+
```
|
|
305
357
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
358
|
+
`authentication(auth)` より後の handler では session state が保証されます。
|
|
359
|
+
|
|
360
|
+
```ts
|
|
361
|
+
const app = new AppsScript()
|
|
362
|
+
.calls(handlers(auth))
|
|
363
|
+
.call("health", () => ({
|
|
364
|
+
ok: true,
|
|
365
|
+
}))
|
|
366
|
+
.use(authentication(auth))
|
|
367
|
+
.call("getProfile", (_input: AuthenticatedInput, context) => {
|
|
368
|
+
const session = context.state.get("session");
|
|
309
369
|
|
|
310
|
-
|
|
370
|
+
return getProfile(session.userId);
|
|
371
|
+
});
|
|
311
372
|
```
|
|
312
373
|
|
|
374
|
+
application 独自の state を追加する場合も、対応する middleware を `.use()` で組み合わせます。
|
|
375
|
+
|
|
313
376
|
## Responsibility
|
|
314
377
|
|
|
315
378
|
`@gasboost/auth-app` が担当するもの:
|
package/dist/authentication.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { AppsScriptMiddleware } from "@gasboost/app";
|
|
2
2
|
import type { AppsScriptAuth } from "@gasboost/auth";
|
|
3
3
|
import type { AuthState } from "./AuthState";
|
|
4
|
-
export declare function authentication(auth: Pick<AppsScriptAuth, "session">): AppsScriptMiddleware<AuthState>;
|
|
4
|
+
export declare function authentication(auth: Pick<AppsScriptAuth, "session">): AppsScriptMiddleware<Record<never, never>, AuthState>;
|
package/dist/authentication.js
CHANGED
|
@@ -7,14 +7,13 @@ function authentication(auth) {
|
|
|
7
7
|
return next();
|
|
8
8
|
}
|
|
9
9
|
const input = context.invocation.input;
|
|
10
|
-
if (typeof input !== "object" ||
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (typeof token !== "string") {
|
|
10
|
+
if (typeof input !== "object" ||
|
|
11
|
+
input === null ||
|
|
12
|
+
!("token" in input) ||
|
|
13
|
+
typeof input.token !== "string") {
|
|
15
14
|
throw new Error("Unauthorized");
|
|
16
15
|
}
|
|
17
|
-
const session = await auth.session.get(token);
|
|
16
|
+
const session = await auth.session.get(input.token);
|
|
18
17
|
if (session === null) {
|
|
19
18
|
throw new Error("Unauthorized");
|
|
20
19
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AppsScriptAuth } from "@gasboost/auth";
|
|
2
|
+
type EmailPasswordOptions = ConstructorParameters<typeof AppsScriptAuth>[0]["emailPassword"];
|
|
3
|
+
type EnabledEmailPasswordOptions = NonNullable<EmailPasswordOptions> & {
|
|
4
|
+
passwordReset: NonNullable<NonNullable<EmailPasswordOptions>["passwordReset"]>;
|
|
5
|
+
};
|
|
6
|
+
type PasswordApi = NonNullable<AppsScriptAuth<EnabledEmailPasswordOptions>["password"]>;
|
|
7
|
+
type Auth<TEmailPassword extends EmailPasswordOptions, THookResult> = AppsScriptAuth<TEmailPassword, THookResult>;
|
|
8
|
+
type BaseHandlers<TEmailPassword extends EmailPasswordOptions, THookResult> = {
|
|
9
|
+
signInEmail: Auth<TEmailPassword, THookResult>["signIn"]["email"];
|
|
10
|
+
signInAppsScript: Auth<TEmailPassword, THookResult>["signIn"]["appsScript"];
|
|
11
|
+
signUpEmail: Auth<TEmailPassword, THookResult>["signUp"]["email"];
|
|
12
|
+
signUpAppsScript: Auth<TEmailPassword, THookResult>["signUp"]["appsScript"];
|
|
13
|
+
getSession: (input: {
|
|
14
|
+
sessionId: Parameters<Auth<TEmailPassword, THookResult>["session"]["get"]>[0];
|
|
15
|
+
}) => ReturnType<Auth<TEmailPassword, THookResult>["session"]["get"]>;
|
|
16
|
+
signOut: (input: {
|
|
17
|
+
sessionId: Parameters<Auth<TEmailPassword, THookResult>["signOut"]["execute"]>[0];
|
|
18
|
+
}) => ReturnType<Auth<TEmailPassword, THookResult>["signOut"]["execute"]>;
|
|
19
|
+
};
|
|
20
|
+
type PasswordHandlers = {
|
|
21
|
+
forgotPassword: PasswordApi["forgot"];
|
|
22
|
+
resetPassword: PasswordApi["reset"];
|
|
23
|
+
};
|
|
24
|
+
export type AuthHandlers<TEmailPassword extends EmailPasswordOptions, THookResult> = BaseHandlers<TEmailPassword, THookResult> & (TEmailPassword extends {
|
|
25
|
+
passwordReset: unknown;
|
|
26
|
+
} ? PasswordHandlers : Record<never, never>);
|
|
27
|
+
export declare function handlers<TEmailPassword extends EmailPasswordOptions, THookResult>(auth: AppsScriptAuth<TEmailPassword, THookResult>): AuthHandlers<TEmailPassword, THookResult>;
|
|
28
|
+
export {};
|
package/dist/handlers.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handlers = handlers;
|
|
4
|
+
function handlers(auth) {
|
|
5
|
+
const baseHandlers = {
|
|
6
|
+
signInEmail: auth.signIn.email,
|
|
7
|
+
signInAppsScript: auth.signIn.appsScript,
|
|
8
|
+
signUpEmail: auth.signUp.email,
|
|
9
|
+
signUpAppsScript: auth.signUp.appsScript,
|
|
10
|
+
getSession: ({ sessionId }) => auth.session.get(sessionId),
|
|
11
|
+
signOut: ({ sessionId }) => auth.signOut.execute(sessionId),
|
|
12
|
+
};
|
|
13
|
+
const password = auth.password;
|
|
14
|
+
if (password === undefined) {
|
|
15
|
+
return baseHandlers;
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
...baseHandlers,
|
|
19
|
+
forgotPassword: password.forgot.bind(password),
|
|
20
|
+
resetPassword: password.reset.bind(password),
|
|
21
|
+
};
|
|
22
|
+
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.authentication = void 0;
|
|
3
|
+
exports.handlers = exports.authentication = void 0;
|
|
4
4
|
var authentication_1 = require("./authentication");
|
|
5
5
|
Object.defineProperty(exports, "authentication", { enumerable: true, get: function () { return authentication_1.authentication; } });
|
|
6
|
+
var handlers_1 = require("./handlers");
|
|
7
|
+
Object.defineProperty(exports, "handlers", { enumerable: true, get: function () { return handlers_1.handlers; } });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gasboost/auth-app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Authentication middleware adapter for @gasboost/auth and @gasboost/app.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"google-apps-script",
|
|
@@ -38,13 +38,13 @@
|
|
|
38
38
|
"access": "public"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"@gasboost/app": "^
|
|
42
|
-
"@gasboost/auth": "^0.
|
|
41
|
+
"@gasboost/app": "^5.0.0",
|
|
42
|
+
"@gasboost/auth": "^0.3.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@gasboost/app": "^
|
|
45
|
+
"@gasboost/app": "^5.0.0",
|
|
46
46
|
"@types/google-apps-script": "^2.0.13",
|
|
47
|
-
"@gasboost/auth": "0.
|
|
47
|
+
"@gasboost/auth": "0.3.0"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
50
|
"format": "prettier --check . --config ../../.prettierrc.json --ignore-path ../../.prettierignore",
|