@toa.io/extensions.exposition 1.0.0-alpha.282 → 1.0.0-alpha.283

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 (312) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/components/exposition.octets/manifest.toa.yaml +11 -0
  3. package/components/exposition.octets/types/index.d.ts +3 -0
  4. package/components/exposition.octets/types/toa.d.ts +41 -0
  5. package/components/identity.bans/types/index.d.ts +3 -0
  6. package/components/identity.bans/types/toa.d.ts +34 -0
  7. package/components/identity.basic/manifest.toa.yaml +13 -2
  8. package/components/identity.basic/operations/add.d.ts +3 -3
  9. package/components/identity.basic/operations/authenticate.d.ts +2 -2
  10. package/components/identity.basic/operations/check.d.ts +1 -1
  11. package/components/identity.basic/operations/delete.d.ts +2 -2
  12. package/components/identity.basic/operations/incept.d.ts +2 -2
  13. package/components/identity.basic/operations/info.d.ts +1 -1
  14. package/components/identity.basic/operations/transit.d.ts +4 -3
  15. package/components/identity.basic/operations/transit.js +2 -1
  16. package/components/identity.basic/operations/transit.js.map +1 -1
  17. package/components/identity.basic/source/add.ts +3 -3
  18. package/components/identity.basic/source/authenticate.ts +2 -2
  19. package/components/identity.basic/source/check.ts +1 -1
  20. package/components/identity.basic/source/delete.ts +2 -2
  21. package/components/identity.basic/source/incept.ts +2 -2
  22. package/components/identity.basic/source/info.ts +1 -1
  23. package/components/identity.basic/source/transit.ts +6 -4
  24. package/components/identity.basic/tsconfig.tsbuildinfo +1 -1
  25. package/components/identity.basic/types/index.d.ts +21 -0
  26. package/components/identity.basic/types/toa.d.ts +121 -0
  27. package/components/identity.clients/manifest.toa.yaml +243 -0
  28. package/components/identity.clients/operations/describe.d.ts +27 -0
  29. package/components/identity.clients/operations/describe.js +44 -0
  30. package/components/identity.clients/operations/describe.js.map +1 -0
  31. package/components/identity.clients/operations/lib/Context.d.ts +29 -0
  32. package/components/identity.clients/operations/lib/Context.js +2 -0
  33. package/components/identity.clients/operations/lib/Context.js.map +1 -0
  34. package/components/identity.clients/operations/lib/Entity.d.ts +29 -0
  35. package/components/identity.clients/operations/lib/Entity.js +2 -0
  36. package/components/identity.clients/operations/lib/Entity.js.map +1 -0
  37. package/components/identity.clients/operations/lib/canonical.d.ts +11 -0
  38. package/components/identity.clients/operations/lib/canonical.js +24 -0
  39. package/components/identity.clients/operations/lib/canonical.js.map +1 -0
  40. package/components/identity.clients/operations/lib/cimd.d.ts +8 -0
  41. package/components/identity.clients/operations/lib/cimd.js +86 -0
  42. package/components/identity.clients/operations/lib/cimd.js.map +1 -0
  43. package/components/identity.clients/operations/lib/errors.d.ts +7 -0
  44. package/components/identity.clients/operations/lib/errors.js +5 -0
  45. package/components/identity.clients/operations/lib/errors.js.map +1 -0
  46. package/components/identity.clients/operations/lib/index.d.ts +6 -0
  47. package/components/identity.clients/operations/lib/index.js +7 -0
  48. package/components/identity.clients/operations/lib/index.js.map +1 -0
  49. package/components/identity.clients/operations/lib/redirect.d.ts +10 -0
  50. package/components/identity.clients/operations/lib/redirect.js +32 -0
  51. package/components/identity.clients/operations/lib/redirect.js.map +1 -0
  52. package/components/identity.clients/operations/register.d.ts +37 -0
  53. package/components/identity.clients/operations/register.js +84 -0
  54. package/components/identity.clients/operations/register.js.map +1 -0
  55. package/components/identity.clients/source/describe.ts +65 -0
  56. package/components/identity.clients/source/lib/Context.ts +38 -0
  57. package/components/identity.clients/source/lib/Entity.ts +31 -0
  58. package/components/identity.clients/source/lib/canonical.test.ts +43 -0
  59. package/components/identity.clients/source/lib/canonical.ts +27 -0
  60. package/components/identity.clients/source/lib/cimd.test.ts +120 -0
  61. package/components/identity.clients/source/lib/cimd.ts +107 -0
  62. package/components/identity.clients/source/lib/errors.ts +4 -0
  63. package/components/identity.clients/source/lib/index.ts +6 -0
  64. package/components/identity.clients/source/lib/redirect.test.ts +41 -0
  65. package/components/identity.clients/source/lib/redirect.ts +35 -0
  66. package/components/identity.clients/source/register.ts +125 -0
  67. package/components/identity.clients/tsconfig.json +10 -0
  68. package/components/identity.clients/tsconfig.tsbuildinfo +1 -0
  69. package/components/identity.clients/types/index.d.ts +3 -0
  70. package/components/identity.clients/types/toa.d.ts +109 -0
  71. package/components/identity.credentials/operations/list.d.ts +2 -1
  72. package/components/identity.credentials/operations/list.js.map +1 -1
  73. package/components/identity.credentials/source/list.ts +2 -1
  74. package/components/identity.credentials/tsconfig.tsbuildinfo +1 -1
  75. package/components/identity.credentials/types/index.d.ts +3 -0
  76. package/components/identity.credentials/types/toa.d.ts +30 -0
  77. package/components/identity.federation/manifest.toa.yaml +37 -1
  78. package/components/identity.federation/operations/authenticate.d.ts +1 -1
  79. package/components/identity.federation/operations/lib/Ctx.d.ts +2 -2
  80. package/components/identity.federation/operations/lib/decode.js +22 -8
  81. package/components/identity.federation/operations/lib/decode.js.map +1 -1
  82. package/components/identity.federation/operations/lib/errors.d.ts +7 -0
  83. package/components/identity.federation/operations/lib/errors.js +4 -0
  84. package/components/identity.federation/operations/lib/errors.js.map +1 -1
  85. package/components/identity.federation/operations/lib/exchange.js +11 -6
  86. package/components/identity.federation/operations/lib/exchange.js.map +1 -1
  87. package/components/identity.federation/operations/types/configuration.d.ts +1 -1
  88. package/components/identity.federation/operations/types/context.d.ts +3 -2
  89. package/components/identity.federation/source/authenticate.ts +1 -1
  90. package/components/identity.federation/source/lib/Ctx.ts +2 -2
  91. package/components/identity.federation/source/lib/decode.ts +25 -9
  92. package/components/identity.federation/source/lib/errors.ts +5 -0
  93. package/components/identity.federation/source/lib/exchange.ts +11 -7
  94. package/components/identity.federation/source/types/configuration.ts +1 -1
  95. package/components/identity.federation/source/types/context.ts +3 -2
  96. package/components/identity.federation/tsconfig.tsbuildinfo +1 -1
  97. package/components/identity.federation/types/index.d.ts +3 -0
  98. package/components/identity.federation/types/toa.d.ts +127 -0
  99. package/components/identity.grants/manifest.toa.yaml +245 -0
  100. package/components/identity.grants/operations/authorize.d.ts +35 -0
  101. package/components/identity.grants/operations/authorize.js +54 -0
  102. package/components/identity.grants/operations/authorize.js.map +1 -0
  103. package/components/identity.grants/operations/exchange.d.ts +37 -0
  104. package/components/identity.grants/operations/exchange.js +89 -0
  105. package/components/identity.grants/operations/exchange.js.map +1 -0
  106. package/components/identity.grants/operations/lib/code.d.ts +15 -0
  107. package/components/identity.grants/operations/lib/code.js +30 -0
  108. package/components/identity.grants/operations/lib/code.js.map +1 -0
  109. package/components/identity.grants/operations/lib/identify.d.ts +6 -0
  110. package/components/identity.grants/operations/lib/identify.js +15 -0
  111. package/components/identity.grants/operations/lib/identify.js.map +1 -0
  112. package/components/identity.grants/operations/lib/index.d.ts +3 -0
  113. package/components/identity.grants/operations/lib/index.js +3 -0
  114. package/components/identity.grants/operations/lib/index.js.map +1 -0
  115. package/components/identity.grants/operations/list.d.ts +13 -0
  116. package/components/identity.grants/operations/list.js +18 -0
  117. package/components/identity.grants/operations/list.js.map +1 -0
  118. package/components/identity.grants/operations/revoke.d.ts +18 -0
  119. package/components/identity.grants/operations/revoke.js +25 -0
  120. package/components/identity.grants/operations/revoke.js.map +1 -0
  121. package/components/identity.grants/source/authorize.ts +90 -0
  122. package/components/identity.grants/source/exchange.ts +130 -0
  123. package/components/identity.grants/source/lib/code.ts +39 -0
  124. package/components/identity.grants/source/lib/identify.ts +16 -0
  125. package/components/identity.grants/source/lib/index.ts +3 -0
  126. package/components/identity.grants/source/list.ts +28 -0
  127. package/components/identity.grants/source/revoke.ts +38 -0
  128. package/components/identity.grants/tsconfig.json +10 -0
  129. package/components/identity.grants/tsconfig.tsbuildinfo +1 -0
  130. package/components/identity.grants/types/index.d.ts +60 -0
  131. package/components/identity.grants/types/toa.d.ts +108 -0
  132. package/components/identity.keys/manifest.toa.yaml +1 -0
  133. package/components/identity.keys/operations/create.d.ts +1 -1
  134. package/components/identity.keys/operations/revoke.d.ts +1 -1
  135. package/components/identity.keys/source/create.ts +1 -1
  136. package/components/identity.keys/source/revoke.ts +1 -1
  137. package/components/identity.keys/tsconfig.tsbuildinfo +1 -1
  138. package/components/identity.keys/types/index.d.ts +3 -0
  139. package/components/identity.keys/types/toa.d.ts +47 -0
  140. package/components/identity.otp/operations/lib/Context.d.ts +4 -2
  141. package/components/identity.otp/source/lib/Context.ts +4 -2
  142. package/components/identity.otp/tsconfig.tsbuildinfo +1 -1
  143. package/components/identity.otp/types/index.d.ts +3 -0
  144. package/components/identity.otp/types/toa.d.ts +56 -0
  145. package/components/identity.passkeys/manifest.toa.yaml +3 -0
  146. package/components/identity.passkeys/operations/authenticate.d.ts +1 -1
  147. package/components/identity.passkeys/operations/challenge.d.ts +1 -1
  148. package/components/identity.passkeys/operations/create.d.ts +1 -1
  149. package/components/identity.passkeys/operations/types/Context.d.ts +2 -1
  150. package/components/identity.passkeys/operations/use.d.ts +1 -1
  151. package/components/identity.passkeys/source/authenticate.ts +1 -1
  152. package/components/identity.passkeys/source/challenge.ts +1 -1
  153. package/components/identity.passkeys/source/create.ts +1 -1
  154. package/components/identity.passkeys/source/types/Context.ts +2 -1
  155. package/components/identity.passkeys/source/use.ts +1 -1
  156. package/components/identity.passkeys/tsconfig.tsbuildinfo +1 -1
  157. package/components/identity.passkeys/types/index.d.ts +3 -0
  158. package/components/identity.passkeys/types/toa.d.ts +120 -0
  159. package/components/identity.roles/operations/principal.d.ts +1 -1
  160. package/components/identity.roles/source/principal.ts +1 -1
  161. package/components/identity.roles/tsconfig.tsbuildinfo +1 -1
  162. package/components/identity.roles/types/index.d.ts +3 -0
  163. package/components/identity.roles/types/toa.d.ts +43 -0
  164. package/components/identity.tokens/manifest.toa.yaml +34 -3
  165. package/components/identity.tokens/operations/authenticate.d.ts +2 -1
  166. package/components/identity.tokens/operations/authenticate.js +8 -0
  167. package/components/identity.tokens/operations/authenticate.js.map +1 -1
  168. package/components/identity.tokens/operations/decrypt.d.ts +2 -1
  169. package/components/identity.tokens/operations/decrypt.js +2 -2
  170. package/components/identity.tokens/operations/decrypt.js.map +1 -1
  171. package/components/identity.tokens/operations/encrypt.d.ts +2 -1
  172. package/components/identity.tokens/operations/encrypt.js.map +1 -1
  173. package/components/identity.tokens/operations/issue.d.ts +2 -1
  174. package/components/identity.tokens/operations/issue.js +2 -1
  175. package/components/identity.tokens/operations/issue.js.map +1 -1
  176. package/components/identity.tokens/operations/lib/form.d.ts +8 -0
  177. package/components/identity.tokens/operations/lib/form.js +24 -0
  178. package/components/identity.tokens/operations/lib/form.js.map +1 -0
  179. package/components/identity.tokens/operations/lib/index.d.ts +2 -1
  180. package/components/identity.tokens/operations/lib/index.js +1 -1
  181. package/components/identity.tokens/operations/lib/index.js.map +1 -1
  182. package/components/identity.tokens/source/authenticate.test.ts +8 -5
  183. package/components/identity.tokens/source/authenticate.ts +12 -1
  184. package/components/identity.tokens/source/decrypt.test.ts +1 -1
  185. package/components/identity.tokens/source/decrypt.ts +4 -3
  186. package/components/identity.tokens/source/encrypt.test.ts +1 -1
  187. package/components/identity.tokens/source/encrypt.ts +2 -1
  188. package/components/identity.tokens/source/issue.test.ts +71 -0
  189. package/components/identity.tokens/source/issue.ts +4 -2
  190. package/components/identity.tokens/source/lib/form.test.ts +25 -0
  191. package/components/identity.tokens/source/lib/form.ts +31 -0
  192. package/components/identity.tokens/source/lib/index.ts +2 -1
  193. package/components/identity.tokens/tsconfig.tsbuildinfo +1 -1
  194. package/components/identity.tokens/types/index.d.ts +61 -0
  195. package/components/identity.tokens/types/toa.d.ts +113 -0
  196. package/documentation/cache.md +10 -1
  197. package/documentation/consent.md +101 -0
  198. package/documentation/identity.md +3 -1
  199. package/documentation/io.md +36 -2
  200. package/documentation/oauth.md +179 -0
  201. package/documentation/protocol.md +4 -0
  202. package/features/auth.bearer.feature +120 -0
  203. package/features/cache.feature +46 -0
  204. package/features/oauth.clients.feature +195 -0
  205. package/features/oauth.discovery.feature +165 -0
  206. package/features/oauth.grants.feature +286 -0
  207. package/features/steps/Gateway.ts +6 -1
  208. package/features/steps/Parameters.ts +4 -0
  209. package/features/steps/components/echo/manifest.toa.yaml +2 -0
  210. package/features/steps/components/octets.tester/manifest.toa.yaml +2 -0
  211. package/features/steps/components/octets.tester/operations/redirect.js +6 -1
  212. package/features/steps/components/users/manifest.toa.yaml +1 -0
  213. package/package.json +8 -6
  214. package/readme.md +3 -0
  215. package/schemas/annotation.cos.yaml +30 -0
  216. package/source/Annotation.ts +23 -0
  217. package/source/Factory.ts +1 -1
  218. package/source/HTTP/Server.ts +9 -5
  219. package/source/HTTP/formats/form.ts +21 -0
  220. package/source/HTTP/formats/index.ts +17 -2
  221. package/source/HTTP/messages.test.ts +25 -1
  222. package/source/HTTP/messages.ts +10 -3
  223. package/source/Interception.ts +8 -2
  224. package/source/deployment.ts +4 -1
  225. package/source/directives/auth/Authorization.ts +46 -19
  226. package/source/directives/auth/Incept.ts +14 -9
  227. package/source/directives/auth/schemes.test.ts +8 -4
  228. package/source/directives/auth/schemes.ts +22 -9
  229. package/source/directives/auth/types.ts +5 -2
  230. package/source/directives/cache/Cache.ts +13 -4
  231. package/source/directives/cache/Control.ts +0 -3
  232. package/source/directives/flow/Fetch.ts +1 -1
  233. package/source/directives/index.ts +2 -1
  234. package/source/directives/io/IO.ts +2 -0
  235. package/source/directives/io/Output.ts +4 -1
  236. package/source/directives/io/Status.test.ts +84 -0
  237. package/source/directives/io/Status.ts +46 -0
  238. package/source/directives/oauth/Discovery.ts +76 -0
  239. package/source/directives/oauth/documents.ts +113 -0
  240. package/source/directives/oauth/index.ts +3 -0
  241. package/source/directives/octets/Delete.ts +1 -1
  242. package/source/directives/octets/Get.ts +1 -1
  243. package/source/directives/octets/Workflow.ts +1 -1
  244. package/source/directives/octets/workflows/Execution.ts +1 -1
  245. package/source/index.ts +6 -0
  246. package/source/octets.d.ts +17 -0
  247. package/source/userland.ts +47 -0
  248. package/transpiled/Annotation.d.ts +17 -0
  249. package/transpiled/Factory.js +1 -1
  250. package/transpiled/Factory.js.map +1 -1
  251. package/transpiled/HTTP/Server.d.ts +4 -1
  252. package/transpiled/HTTP/Server.js +4 -3
  253. package/transpiled/HTTP/Server.js.map +1 -1
  254. package/transpiled/HTTP/formats/form.d.ts +9 -0
  255. package/transpiled/HTTP/formats/form.js +18 -0
  256. package/transpiled/HTTP/formats/form.js.map +1 -0
  257. package/transpiled/HTTP/formats/index.d.ts +10 -2
  258. package/transpiled/HTTP/formats/index.js +10 -0
  259. package/transpiled/HTTP/formats/index.js.map +1 -1
  260. package/transpiled/HTTP/messages.d.ts +6 -0
  261. package/transpiled/HTTP/messages.js +3 -3
  262. package/transpiled/HTTP/messages.js.map +1 -1
  263. package/transpiled/Interception.d.ts +4 -1
  264. package/transpiled/Interception.js +4 -2
  265. package/transpiled/Interception.js.map +1 -1
  266. package/transpiled/deployment.js +2 -0
  267. package/transpiled/deployment.js.map +1 -1
  268. package/transpiled/directives/auth/Authorization.d.ts +1 -1
  269. package/transpiled/directives/auth/Authorization.js +38 -18
  270. package/transpiled/directives/auth/Authorization.js.map +1 -1
  271. package/transpiled/directives/auth/Incept.d.ts +1 -1
  272. package/transpiled/directives/auth/Incept.js +11 -7
  273. package/transpiled/directives/auth/Incept.js.map +1 -1
  274. package/transpiled/directives/auth/schemes.d.ts +16 -4
  275. package/transpiled/directives/auth/schemes.js +20 -8
  276. package/transpiled/directives/auth/schemes.js.map +1 -1
  277. package/transpiled/directives/auth/types.d.ts +4 -2
  278. package/transpiled/directives/cache/Cache.js +9 -2
  279. package/transpiled/directives/cache/Cache.js.map +1 -1
  280. package/transpiled/directives/cache/Control.js +0 -2
  281. package/transpiled/directives/cache/Control.js.map +1 -1
  282. package/transpiled/directives/index.js +2 -1
  283. package/transpiled/directives/index.js.map +1 -1
  284. package/transpiled/directives/io/IO.js +2 -0
  285. package/transpiled/directives/io/IO.js.map +1 -1
  286. package/transpiled/directives/io/Output.js +4 -1
  287. package/transpiled/directives/io/Output.js.map +1 -1
  288. package/transpiled/directives/io/Status.d.ts +19 -0
  289. package/transpiled/directives/io/Status.js +34 -0
  290. package/transpiled/directives/io/Status.js.map +1 -0
  291. package/transpiled/directives/oauth/Discovery.d.ts +23 -0
  292. package/transpiled/directives/oauth/Discovery.js +58 -0
  293. package/transpiled/directives/oauth/Discovery.js.map +1 -0
  294. package/transpiled/directives/oauth/documents.d.ts +9 -0
  295. package/transpiled/directives/oauth/documents.js +82 -0
  296. package/transpiled/directives/oauth/documents.js.map +1 -0
  297. package/transpiled/directives/oauth/index.d.ts +2 -0
  298. package/transpiled/directives/oauth/index.js +3 -0
  299. package/transpiled/directives/oauth/index.js.map +1 -0
  300. package/transpiled/index.d.ts +2 -0
  301. package/transpiled/userland.d.ts +39 -0
  302. package/transpiled/userland.js +7 -0
  303. package/transpiled/userland.js.map +1 -0
  304. package/tsconfig.tsbuildinfo +1 -1
  305. package/components/identity.basic/operations/types.d.ts +0 -61
  306. package/components/identity.basic/operations/types.js +0 -2
  307. package/components/identity.basic/operations/types.js.map +0 -1
  308. package/components/identity.basic/source/types.ts +0 -69
  309. package/components/identity.tokens/operations/lib/types.d.ts +0 -88
  310. package/components/identity.tokens/operations/lib/types.js +0 -2
  311. package/components/identity.tokens/operations/lib/types.js.map +0 -1
  312. package/components/identity.tokens/source/lib/types.ts +0 -102
@@ -0,0 +1,3 @@
1
+ export * from './code.js';
2
+ export * from './identify.js';
3
+ export type * from '../../types/index.js';
@@ -0,0 +1,3 @@
1
+ export * from './code.js';
2
+ export * from './identify.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../source/lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA"}
@@ -0,0 +1,13 @@
1
+ import type { Operation } from '@toa.io/bridges.node';
2
+ import type { Context, Entity } from './lib/index.js';
3
+ /** What a user has allowed, for a screen that lets them take it back. */
4
+ export declare class Computation implements Operation {
5
+ private enumerate;
6
+ mount(context: Context): void;
7
+ execute(input: Input): Promise<Entity[]>;
8
+ }
9
+ interface Input {
10
+ authority: string;
11
+ identity: string;
12
+ }
13
+ export {};
@@ -0,0 +1,18 @@
1
+ import { quote } from '@toa.io/generic';
2
+ /** What a user has allowed, for a screen that lets them take it back. */
3
+ export class Computation {
4
+ enumerate;
5
+ mount(context) {
6
+ this.enumerate = context.local.enumerate;
7
+ }
8
+ async execute(input) {
9
+ return await this.enumerate({
10
+ query: {
11
+ criteria: `authority==${quote(input.authority)};identity==${quote(input.identity)}`,
12
+ limit: LIMIT
13
+ }
14
+ });
15
+ }
16
+ }
17
+ const LIMIT = 256;
18
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../source/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAIvC,yEAAyE;AACzE,MAAM,OAAO,WAAW;IACd,SAAS,CAAgC;IAE1C,KAAK,CAAE,OAAgB;QAC5B,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAA;IAC1C,CAAC;IAEM,KAAK,CAAC,OAAO,CAAE,KAAY;QAChC,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC;YAC1B,KAAK,EAAE;gBACL,QAAQ,EAAE,cAAc,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,cAAc,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE;gBACnF,KAAK,EAAE,KAAK;aACb;SACF,CAAC,CAAA;IACJ,CAAC;CACF;AAED,MAAM,KAAK,GAAG,GAAG,CAAA"}
@@ -0,0 +1,18 @@
1
+ import type { Maybe } from '@toa.io/core';
2
+ import type { Operation } from '@toa.io/bridges.node';
3
+ import type { Context, Entity } from './lib/index.js';
4
+ /**
5
+ * Taking back what was allowed. The token itself is not deleted — it is out in the world —
6
+ * so what is revoked is the key it was issued under, which is what `identity.tokens` reads
7
+ * it with. It stops being a token within `identity.tokens.cache.ttl`.
8
+ */
9
+ export declare class Transition implements Operation {
10
+ private keys;
11
+ mount(context: Context): void;
12
+ execute(input: Input, object: Entity): Promise<Maybe<void>>;
13
+ }
14
+ interface Input {
15
+ authority: string;
16
+ identity: string;
17
+ }
18
+ export {};
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Taking back what was allowed. The token itself is not deleted — it is out in the world —
3
+ * so what is revoked is the key it was issued under, which is what `identity.tokens` reads
4
+ * it with. It stops being a token within `identity.tokens.cache.ttl`.
5
+ */
6
+ export class Transition {
7
+ keys;
8
+ mount(context) {
9
+ this.keys = context.remote.identity.keys;
10
+ }
11
+ async execute(input, object) {
12
+ // the id is a route parameter, so a grant of another identity is asked for by anyone
13
+ // who guesses one; the authority and the identity are what say it is theirs
14
+ if (object._version === 0 || object.authority !== input.authority ||
15
+ object.identity !== input.identity)
16
+ return ERR_NOT_FOUND;
17
+ if (object.kid !== undefined)
18
+ await this.keys.disable({ query: { id: object.kid } });
19
+ object.revokedAt = Date.now();
20
+ }
21
+ }
22
+ const ERR_NOT_FOUND = new (class NotFoundError extends Error {
23
+ code = 'NOT_FOUND';
24
+ })();
25
+ //# sourceMappingURL=revoke.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revoke.js","sourceRoot":"","sources":["../source/revoke.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,MAAM,OAAO,UAAU;IACb,IAAI,CAAwC;IAE7C,KAAK,CAAE,OAAgB;QAC5B,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAA;IAC1C,CAAC;IAEM,KAAK,CAAC,OAAO,CAAE,KAAY,EAAE,MAAc;QAChD,qFAAqF;QACrF,4EAA4E;QAC5E,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,IAAI,MAAM,CAAC,SAAS,KAAK,KAAK,CAAC,SAAS;YAC/D,MAAM,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ;YAClC,OAAO,aAAa,CAAA;QAEtB,IAAI,MAAM,CAAC,GAAG,KAAK,SAAS;YAC1B,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;QAExD,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IAC/B,CAAC;CACF;AAED,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,aAAc,SAAQ,KAAK;IAC1C,IAAI,GAAG,WAAW,CAAA;CACnC,CAAC,EAAE,CAAA"}
@@ -0,0 +1,90 @@
1
+ import { hold, identify } from './lib/index.js'
2
+ import type { Maybe } from '@toa.io/core'
3
+ import type { Operation } from '@toa.io/bridges.node'
4
+ import type { Context } from './lib/index.js'
5
+
6
+ /**
7
+ * What the consent page calls when a user allows a client. The page holds the user's own
8
+ * credentials, so this is the user's own route; the code it answers with is what the client
9
+ * redeems at the token endpoint.
10
+ *
11
+ * The grant is recorded so a user can see what they allowed and take it back. It is not
12
+ * consulted to skip the prompt — consent is asked every time, which is what keeps a client
13
+ * that changed where it wants a code sent from being waved through on an older one.
14
+ */
15
+ export class Effect implements Operation {
16
+ private context!: Context
17
+
18
+ public mount (context: Context): void {
19
+ this.context = context
20
+ }
21
+
22
+ public async execute (input: Input): Promise<Maybe<Output>> {
23
+ const { authority, identity } = input
24
+
25
+ if (input.method !== S256)
26
+ return invalid('invalid_request', 'Only the S256 code challenge method is supported')
27
+
28
+ const client = await this.context.remote.identity.clients.describe({
29
+ input: { authority, id: input.client, redirect: input.redirect }
30
+ })
31
+
32
+ if (client instanceof Error)
33
+ return invalid('invalid_client', 'No such client')
34
+
35
+ if (client.permitted !== true)
36
+ return invalid('invalid_request', 'The redirect is not one this client may receive a code at')
37
+
38
+ const scope = input.scope ?? []
39
+
40
+ // recorded on the grant and carried to the token endpoint, and restricting nothing yet:
41
+ // a token carries the rights of the identity that consented, over every path it may
42
+ // reach. What binds it is a `permissions` argument in `exchange`, see documentation/oauth.md
43
+ const resource = input.resource ?? []
44
+
45
+ const grant = await this.context.local.transit({
46
+ query: { id: identify(authority, identity, input.client) },
47
+ input: { authority, identity, client: input.client, scope, resource }
48
+ })
49
+
50
+ if (grant instanceof Error)
51
+ return grant
52
+
53
+ const code = await hold(authority, {
54
+ identity,
55
+ client: input.client,
56
+ redirect: input.redirect,
57
+ challenge: input.challenge,
58
+ scope,
59
+ resource
60
+ }, this.context)
61
+
62
+ return { code, expires_in: this.context.configuration.lifetime }
63
+ }
64
+ }
65
+
66
+ function invalid (error: string, description: string): Output {
67
+ return { status: BAD_REQUEST, error, error_description: description }
68
+ }
69
+
70
+ const S256 = 'S256'
71
+ const BAD_REQUEST = 400
72
+
73
+ interface Input {
74
+ authority: string
75
+ identity: string
76
+ client: string
77
+ redirect: string
78
+ challenge: string
79
+ method: string
80
+ scope?: string[]
81
+ resource?: string[]
82
+ }
83
+
84
+ interface Output {
85
+ status?: number
86
+ code?: string
87
+ expires_in?: number
88
+ error?: string
89
+ error_description?: string
90
+ }
@@ -0,0 +1,130 @@
1
+ import { identify, spend, verifies } from './lib/index.js'
2
+ import type { Maybe } from '@toa.io/core'
3
+ import type { Operation } from '@toa.io/bridges.node'
4
+ import type { Code, Context } from './lib/index.js'
5
+
6
+ /**
7
+ * The token endpoint, RFC 6749 §4.1.3. Anonymous, because the clients this server knows are
8
+ * public ones with no secret to authenticate with: what stands in for that is PKCE, since
9
+ * only the client that began the flow holds the verifier the challenge was made from.
10
+ *
11
+ * Every failure here is `invalid_grant` without saying which check failed. A code that was
12
+ * replayed, a verifier that does not match and a redirect that was swapped are all the same
13
+ * answer, and telling them apart would say whether a stolen code was still live.
14
+ */
15
+ export class Effect implements Operation {
16
+ private context!: Context
17
+
18
+ public mount (context: Context): void {
19
+ this.context = context
20
+ }
21
+
22
+ public async execute (input: Input): Promise<Maybe<Output>> {
23
+ const { authority } = input
24
+
25
+ if (input.grant_type !== AUTHORIZATION_CODE)
26
+ return invalid('unsupported_grant_type', 'Only the authorization code grant is supported')
27
+
28
+ if (input.code === undefined || input.code_verifier === undefined)
29
+ return invalid('invalid_request', 'A code and a code verifier are required')
30
+
31
+ // spent first: a wrong verifier burns the code, which is what stops it being guessed at
32
+ const code = await spend(authority, input.code, this.context)
33
+
34
+ if (code === null || !this.redeemable(code, input))
35
+ return invalid('invalid_grant', 'The authorization code is not redeemable')
36
+
37
+ // `permissions` would bind the token to `code.resource` — `{'/mcp/**': ['*']}` for a
38
+ // resource at `/mcp/`, which `permits()` reads on every request. Left unset: the token
39
+ // carries the rights of the identity that consented, see documentation/oauth.md#audience
40
+ const issued = await this.context.remote.identity.tokens.issue({
41
+ input: {
42
+ authority,
43
+ identity: code.identity,
44
+ label: label(code.client),
45
+ lifetime: this.context.configuration.token,
46
+ ...(code.scope.length === 0 ? {} : { scopes: code.scope })
47
+ }
48
+ })
49
+
50
+ // the only refusal `issue` makes is a scope the consenting identity does not hold, and
51
+ // what it says about that is its own; the client is told what it may act on
52
+ if (issued instanceof Error)
53
+ return invalid('invalid_scope', 'The requested scope is not one the identity holds')
54
+
55
+ // the key the token was issued under, so revoking the grant revokes the token. The token
56
+ // is already out, so a grant that fails to record it is logged rather than unwound — it
57
+ // costs the user the ability to revoke, and refusing here would cost them the token too
58
+ const grant = await this.context.local.transit({
59
+ query: { id: identify(authority, code.identity, code.client) },
60
+ input: {
61
+ authority,
62
+ identity: code.identity,
63
+ client: code.client,
64
+ scope: code.scope,
65
+ resource: code.resource,
66
+ kid: issued.kid
67
+ }
68
+ })
69
+
70
+ if (grant instanceof Error)
71
+ this.context.logs.error('Grant not recorded for an issued token',
72
+ { client: code.client, kid: issued.kid })
73
+
74
+ return {
75
+ // RFC 6749 §5.1 asks for 200, where a POST would otherwise answer 201
76
+ status: OK,
77
+ access_token: issued.token,
78
+ token_type: 'Bearer',
79
+ ...(issued.exp === undefined
80
+ ? {}
81
+ : { expires_in: Math.floor((issued.exp - Date.now()) / 1000) }),
82
+ ...(code.scope.length === 0 ? {} : { scope: code.scope.join(' ') })
83
+ }
84
+ }
85
+
86
+ private redeemable (code: Code, input: Input): boolean {
87
+ if (!verifies(code.challenge, input.code_verifier!))
88
+ return false
89
+
90
+ // RFC 6749 §4.1.3: what was sent to `authorize` must be sent again
91
+ if (input.redirect_uri !== undefined && input.redirect_uri !== code.redirect)
92
+ return false
93
+
94
+ return input.client_id === undefined || input.client_id === code.client
95
+ }
96
+ }
97
+
98
+ /** `identity.tokens` requires one, and it is what a user sees when listing what they issued. */
99
+ function label (client: string): string {
100
+ return client.slice(0, LABEL)
101
+ }
102
+
103
+ function invalid (error: string, description: string): Output {
104
+ return { status: BAD_REQUEST, error, error_description: description }
105
+ }
106
+
107
+ const AUTHORIZATION_CODE = 'authorization_code'
108
+ const OK = 200
109
+ const BAD_REQUEST = 400
110
+ const LABEL = 64
111
+
112
+ interface Input {
113
+ authority: string
114
+ grant_type: string
115
+ code?: string
116
+ code_verifier?: string
117
+ redirect_uri?: string
118
+ client_id?: string
119
+ resource?: string | string[]
120
+ }
121
+
122
+ interface Output {
123
+ status?: number
124
+ access_token?: string
125
+ token_type?: string
126
+ expires_in?: number
127
+ scope?: string
128
+ error?: string
129
+ error_description?: string
130
+ }
@@ -0,0 +1,39 @@
1
+ import { createHash, randomBytes } from 'node:crypto'
2
+ import type { Code, Context } from '../../types/index.js'
3
+
4
+ /**
5
+ * An authorization code is a bearer credential that lives for seconds. It is held under a
6
+ * hash of itself, so a dump of the store hands out none of them, and redeemed with `GETDEL`,
7
+ * so it is spent once however many requests arrive at once — the property the whole flow
8
+ * rests on, since a replayed code is a stolen grant.
9
+ */
10
+ export async function hold (authority: string, code: Code, context: Context): Promise<string> {
11
+ const value = randomBytes(32).toString('base64url')
12
+
13
+ await context.stash.set(key(authority, value), JSON.stringify(code),
14
+ 'EX', context.configuration.lifetime)
15
+
16
+ return value
17
+ }
18
+
19
+ export async function spend (authority: string, value: string, context: Context): Promise<Code | null> {
20
+ const held = await context.stash.getdel(key(authority, value))
21
+
22
+ return held === null ? null : JSON.parse(held) as Code
23
+ }
24
+
25
+ /**
26
+ * PKCE, RFC 7636: the client kept a verifier and sent its hash, and only the client that
27
+ * began the flow can present the verifier now. `S256` alone — `plain` proves nothing.
28
+ */
29
+ export function verifies (challenge: string, verifier: string): boolean {
30
+ return digest(verifier) === challenge
31
+ }
32
+
33
+ export function digest (verifier: string): string {
34
+ return createHash('sha256').update(verifier).digest('base64url')
35
+ }
36
+
37
+ function key (authority: string, value: string): string {
38
+ return `oauth:code:${authority}:${createHash('sha256').update(value).digest('hex')}`
39
+ }
@@ -0,0 +1,16 @@
1
+ import { createHash } from 'node:crypto'
2
+
3
+ /**
4
+ * A user holds one grant per client, so the record is addressed by the three things that
5
+ * say which: authorizing again replaces what is there rather than leaving another row, and
6
+ * revoking has one thing to revoke.
7
+ */
8
+ export function identify (authority: string, identity: string, client: string): string {
9
+ return createHash('sha256')
10
+ .update(JSON.stringify([authority, identity, client]))
11
+ .digest('hex')
12
+ .slice(0, LENGTH)
13
+ }
14
+
15
+ /** What the entity prototype accepts as an id. */
16
+ const LENGTH = 32
@@ -0,0 +1,3 @@
1
+ export * from './code.js'
2
+ export * from './identify.js'
3
+ export type * from '../../types/index.js'
@@ -0,0 +1,28 @@
1
+ import { quote } from '@toa.io/generic'
2
+ import type { Operation } from '@toa.io/bridges.node'
3
+ import type { Context, Entity } from './lib/index.js'
4
+
5
+ /** What a user has allowed, for a screen that lets them take it back. */
6
+ export class Computation implements Operation {
7
+ private enumerate!: Context['local']['enumerate']
8
+
9
+ public mount (context: Context): void {
10
+ this.enumerate = context.local.enumerate
11
+ }
12
+
13
+ public async execute (input: Input): Promise<Entity[]> {
14
+ return await this.enumerate({
15
+ query: {
16
+ criteria: `authority==${quote(input.authority)};identity==${quote(input.identity)}`,
17
+ limit: LIMIT
18
+ }
19
+ })
20
+ }
21
+ }
22
+
23
+ const LIMIT = 256
24
+
25
+ interface Input {
26
+ authority: string
27
+ identity: string
28
+ }
@@ -0,0 +1,38 @@
1
+ import type { Maybe } from '@toa.io/core'
2
+ import type { Operation } from '@toa.io/bridges.node'
3
+ import type { Context, Entity } from './lib/index.js'
4
+
5
+ /**
6
+ * Taking back what was allowed. The token itself is not deleted — it is out in the world —
7
+ * so what is revoked is the key it was issued under, which is what `identity.tokens` reads
8
+ * it with. It stops being a token within `identity.tokens.cache.ttl`.
9
+ */
10
+ export class Transition implements Operation {
11
+ private keys!: Context['remote']['identity']['keys']
12
+
13
+ public mount (context: Context): void {
14
+ this.keys = context.remote.identity.keys
15
+ }
16
+
17
+ public async execute (input: Input, object: Entity): Promise<Maybe<void>> {
18
+ // the id is a route parameter, so a grant of another identity is asked for by anyone
19
+ // who guesses one; the authority and the identity are what say it is theirs
20
+ if (object._version === 0 || object.authority !== input.authority ||
21
+ object.identity !== input.identity)
22
+ return ERR_NOT_FOUND
23
+
24
+ if (object.kid !== undefined)
25
+ await this.keys.disable({ query: { id: object.kid } })
26
+
27
+ object.revokedAt = Date.now()
28
+ }
29
+ }
30
+
31
+ const ERR_NOT_FOUND = new (class NotFoundError extends Error {
32
+ public readonly code = 'NOT_FOUND'
33
+ })()
34
+
35
+ interface Input {
36
+ authority: string
37
+ identity: string
38
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./operations",
5
+ "rootDir": "./source"
6
+ },
7
+ "include": [
8
+ "source"
9
+ ]
10
+ }