Attic is a cozy space with lofty ambitions. attic.social

basic oauth callback

dbushell.com f5dc2e34 9804c403

verified
+393 -24
+10
package.json
··· 19 19 "svelte-check": "^4.4.2", 20 20 "typescript": "^5.9.3", 21 21 "vite": "^7.3.1" 22 + }, 23 + "dependencies": { 24 + "@atcute/atproto": "^3.1.10", 25 + "@atcute/bluesky": "^3.2.20", 26 + "@atcute/client": "^4.2.1", 27 + "@atcute/identity-resolver": "^1.2.2", 28 + "@atcute/identity-resolver-node": "^1.0.3", 29 + "@atcute/lexicons": "^1.2.9", 30 + "@atcute/oauth-node-client": "^1.1.0", 31 + "@types/node": "^25.3.3" 22 32 } 23 33 }
+209 -19
pnpm-lock.yaml
··· 7 7 importers: 8 8 9 9 .: 10 + dependencies: 11 + '@atcute/atproto': 12 + specifier: ^3.1.10 13 + version: 3.1.10 14 + '@atcute/bluesky': 15 + specifier: ^3.2.20 16 + version: 3.2.20 17 + '@atcute/client': 18 + specifier: ^4.2.1 19 + version: 4.2.1 20 + '@atcute/identity-resolver': 21 + specifier: ^1.2.2 22 + version: 1.2.2(@atcute/identity@1.1.3) 23 + '@atcute/identity-resolver-node': 24 + specifier: ^1.0.3 25 + version: 1.0.3(@atcute/identity-resolver@1.2.2(@atcute/identity@1.1.3))(@atcute/identity@1.1.3) 26 + '@atcute/lexicons': 27 + specifier: ^1.2.9 28 + version: 1.2.9 29 + '@atcute/oauth-node-client': 30 + specifier: ^1.1.0 31 + version: 1.1.0 32 + '@types/node': 33 + specifier: ^25.3.3 34 + version: 25.3.3 10 35 devDependencies: 11 36 '@sveltejs/adapter-auto': 12 37 specifier: ^7.0.0 13 - version: 7.0.1(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1)) 38 + version: 7.0.1(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.3)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3))) 14 39 '@sveltejs/kit': 15 40 specifier: ^2.50.2 16 - version: 2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1) 41 + version: 2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.3)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)) 17 42 '@sveltejs/vite-plugin-svelte': 18 43 specifier: ^6.2.4 19 - version: 6.2.4(svelte@5.53.7)(vite@7.3.1) 44 + version: 6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.3)) 20 45 svelte: 21 46 specifier: ^5.51.0 22 47 version: 5.53.7 ··· 28 53 version: 5.9.3 29 54 vite: 30 55 specifier: ^7.3.1 31 - version: 7.3.1 56 + version: 7.3.1(@types/node@25.3.3) 32 57 33 58 packages: 59 + 60 + '@atcute/atproto@3.1.10': 61 + resolution: {integrity: sha512-+GKZpOc0PJcdWMQEkTfg/rSNDAAHxmAUGBl60g2az15etqJn5WaUPNGFE2sB7hKpwi5Ue2h/L0OacINcE/JDDQ==} 62 + 63 + '@atcute/bluesky@3.2.20': 64 + resolution: {integrity: sha512-N+o7K31ptnHSFoYKOHfQYJHFqU7CgGbCX8lDeWvpQuwkEMTEPojrQXIQD/+FL+FVEvRV/84LNi9cEnhPKShE5w==} 65 + 66 + '@atcute/client@4.2.1': 67 + resolution: {integrity: sha512-ZBFM2pW075JtgGFu5g7HHZBecrClhlcNH8GVP9Zz1aViWR+cjjBsTpeE63rJs+FCOHFYlirUyo5L8SGZ4kMINw==} 68 + 69 + '@atcute/identity-resolver-node@1.0.3': 70 + resolution: {integrity: sha512-RPH5M4ZRayKRcGnJWUOPVhN5WSYURXXZxKzgVT9lj/WZCH6ij2Vg3P3Eva7GGs0SG1ytnX1XVBTMoIk8nF/SLQ==} 71 + peerDependencies: 72 + '@atcute/identity': ^1.0.0 73 + '@atcute/identity-resolver': ^1.0.0 74 + 75 + '@atcute/identity-resolver@1.2.2': 76 + resolution: {integrity: sha512-eUh/UH4bFvuXS0X7epYCeJC/kj4rbBXfSRumLEH4smMVwNOgTo7cL/0Srty+P/qVPoZEyXdfEbS0PHJyzoXmHw==} 77 + peerDependencies: 78 + '@atcute/identity': ^1.0.0 79 + 80 + '@atcute/identity@1.1.3': 81 + resolution: {integrity: sha512-oIqPoI8TwWeQxvcLmFEZLdN2XdWcaLVtlm8pNk0E72As9HNzzD9pwKPrLr3rmTLRIoULPPFmq9iFNsTeCIU9ng==} 82 + 83 + '@atcute/lexicons@1.2.9': 84 + resolution: {integrity: sha512-/RRHm2Cw9o8Mcsrq0eo8fjS9okKYLGfuFwrQ0YoP/6sdSDsXshaTLJsvLlcUcaDaSJ1YFOuHIo3zr2Om2F/16g==} 85 + 86 + '@atcute/multibase@1.1.8': 87 + resolution: {integrity: sha512-pJgtImMZKCjqwRbu+2GzB+4xQjKBXDwdZOzeqe0u97zYKRGftpGYGvYv3+pMe2xXe+msDyu7Nv8iJp+U14otTA==} 88 + 89 + '@atcute/oauth-crypto@0.1.0': 90 + resolution: {integrity: sha512-qZYDCNLF/4B6AndYT1rsQelN8621AC5u/sL5PHvlr/qqAbmmUwCBGjEgRSyZtHE1AqD60VNiSMlOgAuEQTSl3w==} 91 + 92 + '@atcute/oauth-keyset@0.1.0': 93 + resolution: {integrity: sha512-+wqT/+I5Lg9VzKnKY3g88+N45xbq+wsdT6bHDGqCVa2u57gRvolFF4dY+weMfc/OX641BIZO6/o+zFtKBsMQnQ==} 94 + 95 + '@atcute/oauth-node-client@1.1.0': 96 + resolution: {integrity: sha512-xCp/VfjtvTeKscKR/oI2hdMTp1/DaF/7ll8b6yZOCgbKlVDDfhCn5mmKNVARGTNaoywxrXG3XffbWCIx3/E87w==} 97 + 98 + '@atcute/oauth-types@0.1.1': 99 + resolution: {integrity: sha512-u+3KMjse3Uc/9hDyilu1QVN7IpcnjVXgRzhddzBB8Uh6wePHNVBDdi9wQvFTVVA3zmxtMJVptXRyLLg6Ou9bqg==} 100 + 101 + '@atcute/uint8array@1.1.1': 102 + resolution: {integrity: sha512-3LsC8XB8TKe9q/5hOA5sFuzGaIFdJZJNewC5OKa3o/eU6+K7JR6see9Zy2JbQERNVnRl11EzbNov1efgLMAs4g==} 103 + 104 + '@atcute/util-fetch@1.0.5': 105 + resolution: {integrity: sha512-qjHj01BGxjSjIFdPiAjSARnodJIIyKxnCMMEcXMESo9TAyND6XZQqrie5fia+LlYWVXdpsTds8uFQwc9jdKTig==} 106 + 107 + '@atcute/util-text@1.1.1': 108 + resolution: {integrity: sha512-JH0SxzUQJAmbOBTYyhxQbkkI6M33YpjlVLEcbP5GYt43xgFArzV0FJVmEpvIj0kjsmphHB45b6IitdvxPdec9w==} 109 + 110 + '@badrap/valita@0.4.6': 111 + resolution: {integrity: sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg==} 112 + engines: {node: '>= 18'} 34 113 35 114 '@esbuild/aix-ppc64@0.27.3': 36 115 resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} ··· 395 474 '@types/estree@1.0.8': 396 475 resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} 397 476 477 + '@types/node@25.3.3': 478 + resolution: {integrity: sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==} 479 + 398 480 '@types/trusted-types@2.0.7': 399 481 resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} 400 482 ··· 481 563 engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 482 564 hasBin: true 483 565 566 + nanoid@5.1.6: 567 + resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==} 568 + engines: {node: ^18 || >=20} 569 + hasBin: true 570 + 484 571 obug@2.1.1: 485 572 resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} 486 573 ··· 543 630 resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} 544 631 engines: {node: '>=14.17'} 545 632 hasBin: true 633 + 634 + undici-types@7.18.2: 635 + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} 636 + 637 + unicode-segmenter@0.14.5: 638 + resolution: {integrity: sha512-jHGmj2LUuqDcX3hqY12Ql+uhUTn8huuxNZGq7GvtF6bSybzH3aFgedYu/KTzQStEgt1Ra2F3HxadNXsNjb3m3g==} 546 639 547 640 vite@7.3.1: 548 641 resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} ··· 597 690 598 691 snapshots: 599 692 693 + '@atcute/atproto@3.1.10': 694 + dependencies: 695 + '@atcute/lexicons': 1.2.9 696 + 697 + '@atcute/bluesky@3.2.20': 698 + dependencies: 699 + '@atcute/atproto': 3.1.10 700 + '@atcute/lexicons': 1.2.9 701 + 702 + '@atcute/client@4.2.1': 703 + dependencies: 704 + '@atcute/identity': 1.1.3 705 + '@atcute/lexicons': 1.2.9 706 + 707 + '@atcute/identity-resolver-node@1.0.3(@atcute/identity-resolver@1.2.2(@atcute/identity@1.1.3))(@atcute/identity@1.1.3)': 708 + dependencies: 709 + '@atcute/identity': 1.1.3 710 + '@atcute/identity-resolver': 1.2.2(@atcute/identity@1.1.3) 711 + '@atcute/lexicons': 1.2.9 712 + 713 + '@atcute/identity-resolver@1.2.2(@atcute/identity@1.1.3)': 714 + dependencies: 715 + '@atcute/identity': 1.1.3 716 + '@atcute/lexicons': 1.2.9 717 + '@atcute/util-fetch': 1.0.5 718 + '@badrap/valita': 0.4.6 719 + 720 + '@atcute/identity@1.1.3': 721 + dependencies: 722 + '@atcute/lexicons': 1.2.9 723 + '@badrap/valita': 0.4.6 724 + 725 + '@atcute/lexicons@1.2.9': 726 + dependencies: 727 + '@atcute/uint8array': 1.1.1 728 + '@atcute/util-text': 1.1.1 729 + '@standard-schema/spec': 1.1.0 730 + esm-env: 1.2.2 731 + 732 + '@atcute/multibase@1.1.8': 733 + dependencies: 734 + '@atcute/uint8array': 1.1.1 735 + 736 + '@atcute/oauth-crypto@0.1.0': 737 + dependencies: 738 + '@atcute/multibase': 1.1.8 739 + '@atcute/uint8array': 1.1.1 740 + '@badrap/valita': 0.4.6 741 + nanoid: 5.1.6 742 + 743 + '@atcute/oauth-keyset@0.1.0': 744 + dependencies: 745 + '@atcute/oauth-crypto': 0.1.0 746 + 747 + '@atcute/oauth-node-client@1.1.0': 748 + dependencies: 749 + '@atcute/client': 4.2.1 750 + '@atcute/identity': 1.1.3 751 + '@atcute/identity-resolver': 1.2.2(@atcute/identity@1.1.3) 752 + '@atcute/lexicons': 1.2.9 753 + '@atcute/oauth-crypto': 0.1.0 754 + '@atcute/oauth-keyset': 0.1.0 755 + '@atcute/oauth-types': 0.1.1 756 + '@atcute/util-fetch': 1.0.5 757 + '@badrap/valita': 0.4.6 758 + nanoid: 5.1.6 759 + 760 + '@atcute/oauth-types@0.1.1': 761 + dependencies: 762 + '@atcute/identity': 1.1.3 763 + '@atcute/lexicons': 1.2.9 764 + '@atcute/oauth-keyset': 0.1.0 765 + '@badrap/valita': 0.4.6 766 + 767 + '@atcute/uint8array@1.1.1': {} 768 + 769 + '@atcute/util-fetch@1.0.5': 770 + dependencies: 771 + '@badrap/valita': 0.4.6 772 + 773 + '@atcute/util-text@1.1.1': 774 + dependencies: 775 + unicode-segmenter: 0.14.5 776 + 777 + '@badrap/valita@0.4.6': {} 778 + 600 779 '@esbuild/aix-ppc64@0.27.3': 601 780 optional: true 602 781 ··· 777 956 dependencies: 778 957 acorn: 8.16.0 779 958 780 - '@sveltejs/adapter-auto@7.0.1(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1))': 959 + '@sveltejs/adapter-auto@7.0.1(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.3)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)))': 781 960 dependencies: 782 - '@sveltejs/kit': 2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1) 961 + '@sveltejs/kit': 2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.3)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3)) 783 962 784 - '@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1)': 963 + '@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.3)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.3))': 785 964 dependencies: 786 965 '@standard-schema/spec': 1.1.0 787 966 '@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0) 788 - '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.53.7)(vite@7.3.1) 967 + '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.3)) 789 968 '@types/cookie': 0.6.0 790 969 acorn: 8.16.0 791 970 cookie: 0.6.0 ··· 797 976 set-cookie-parser: 3.0.1 798 977 sirv: 3.0.2 799 978 svelte: 5.53.7 800 - vite: 7.3.1 979 + vite: 7.3.1(@types/node@25.3.3) 801 980 optionalDependencies: 802 981 typescript: 5.9.3 803 982 804 - '@sveltejs/vite-plugin-svelte-inspector@5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1))(svelte@5.53.7)(vite@7.3.1)': 983 + '@sveltejs/vite-plugin-svelte-inspector@5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.3)))(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.3))': 805 984 dependencies: 806 - '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.53.7)(vite@7.3.1) 985 + '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.3)) 807 986 obug: 2.1.1 808 987 svelte: 5.53.7 809 - vite: 7.3.1 988 + vite: 7.3.1(@types/node@25.3.3) 810 989 811 - '@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1)': 990 + '@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.3))': 812 991 dependencies: 813 - '@sveltejs/vite-plugin-svelte-inspector': 5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1))(svelte@5.53.7)(vite@7.3.1) 992 + '@sveltejs/vite-plugin-svelte-inspector': 5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.3)))(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.3)) 814 993 deepmerge: 4.3.1 815 994 magic-string: 0.30.21 816 995 obug: 2.1.1 817 996 svelte: 5.53.7 818 - vite: 7.3.1 819 - vitefu: 1.1.2(vite@7.3.1) 997 + vite: 7.3.1(@types/node@25.3.3) 998 + vitefu: 1.1.2(vite@7.3.1(@types/node@25.3.3)) 820 999 821 1000 '@types/cookie@0.6.0': {} 822 1001 823 1002 '@types/estree@1.0.8': {} 824 1003 1004 + '@types/node@25.3.3': 1005 + dependencies: 1006 + undici-types: 7.18.2 1007 + 825 1008 '@types/trusted-types@2.0.7': {} 826 1009 827 1010 acorn@8.16.0: {} ··· 901 1084 mrmime@2.0.1: {} 902 1085 903 1086 nanoid@3.3.11: {} 1087 + 1088 + nanoid@5.1.6: {} 904 1089 905 1090 obug@2.1.1: {} 906 1091 ··· 1001 1186 1002 1187 typescript@5.9.3: {} 1003 1188 1004 - vite@7.3.1: 1189 + undici-types@7.18.2: {} 1190 + 1191 + unicode-segmenter@0.14.5: {} 1192 + 1193 + vite@7.3.1(@types/node@25.3.3): 1005 1194 dependencies: 1006 1195 esbuild: 0.27.3 1007 1196 fdir: 6.5.0(picomatch@4.0.3) ··· 1010 1199 rollup: 4.59.0 1011 1200 tinyglobby: 0.2.15 1012 1201 optionalDependencies: 1202 + '@types/node': 25.3.3 1013 1203 fsevents: 2.3.3 1014 1204 1015 - vitefu@1.1.2(vite@7.3.1): 1205 + vitefu@1.1.2(vite@7.3.1(@types/node@25.3.3)): 1016 1206 optionalDependencies: 1017 - vite: 7.3.1 1207 + vite: 7.3.1(@types/node@25.3.3) 1018 1208 1019 1209 zimmerframe@1.1.4: {}
+60
src/lib/server/oauth.ts
··· 1 + import { 2 + CompositeDidDocumentResolver, 3 + CompositeHandleResolver, 4 + LocalActorResolver, 5 + PlcDidDocumentResolver, 6 + WebDidDocumentResolver, 7 + WellKnownHandleResolver, 8 + } from "@atcute/identity-resolver"; 9 + import { NodeDnsHandleResolver } from "@atcute/identity-resolver-node"; 10 + import { 11 + MemoryStore, 12 + OAuthClient, 13 + scope, 14 + type StoredState, 15 + } from "@atcute/oauth-node-client"; 16 + 17 + const TEN_MINUTES_MS = 10 * 60_000; 18 + 19 + /** 20 + * {@link https://github.com/mary-ext/atcute/tree/trunk/packages/oauth/node-client-public-example} 21 + */ 22 + export function createOAuthClient() { 23 + // [TODO] dynamic hostname/port 24 + const redirectUri = `http://127.0.0.1:5173/oauth/callback`; 25 + 26 + const client = new OAuthClient({ 27 + metadata: { 28 + redirect_uris: [redirectUri], 29 + scope: [scope.rpc({ lxm: ["app.bsky.actor.getProfile"], aud: "*" })], 30 + }, 31 + 32 + actorResolver: new LocalActorResolver({ 33 + handleResolver: new CompositeHandleResolver({ 34 + methods: { 35 + dns: new NodeDnsHandleResolver(), 36 + http: new WellKnownHandleResolver(), 37 + }, 38 + }), 39 + didDocumentResolver: new CompositeDidDocumentResolver({ 40 + methods: { 41 + plc: new PlcDidDocumentResolver(), 42 + web: new WebDidDocumentResolver(), 43 + }, 44 + }), 45 + }), 46 + // [TODO] custom database K/V store 47 + stores: { 48 + sessions: new MemoryStore({ maxSize: 10 }), 49 + states: new MemoryStore<string, StoredState>({ 50 + maxSize: 10, 51 + ttl: TEN_MINUTES_MS, 52 + ttlAutopurge: true, 53 + }), 54 + }, 55 + }); 56 + 57 + return client; 58 + } 59 + 60 + export const oAuthClient = createOAuthClient();
+40
src/routes/+page.server.ts
··· 1 + import { type Actions, fail, redirect } from "@sveltejs/kit"; 2 + import { isActorIdentifier } from "@atcute/lexicons/syntax"; 3 + // import crypto from "node:crypto"; 4 + import { oAuthClient } from "$lib/server/oauth.ts"; 5 + // import { dev } from "$app/environment"; 6 + 7 + export const actions = { 8 + login: async ({ request }) => { 9 + const formData = await request.formData(); 10 + const handle = formData.get("handle"); 11 + 12 + if (isActorIdentifier(handle) === false) { 13 + return fail(400, { handle, invalid: true }); 14 + } 15 + const { url } = await oAuthClient.authorize({ 16 + target: { 17 + "type": "account", 18 + identifier: handle, 19 + }, 20 + // scope: [ 21 + // "atproto", 22 + // ].join(" "), 23 + }); 24 + // [TODO] delete / handled by @atcute? 25 + // cookies.set( 26 + // "atproto_oauth_request", 27 + // crypto.createHash("sha256") 28 + // .update(stateId, "utf8") 29 + // .digest("hex"), 30 + // { 31 + // httpOnly: true, 32 + // maxAge: 60 * 5, 33 + // path: "/", 34 + // secure: !dev, 35 + // sameSite: "lax", 36 + // }, 37 + // ); 38 + redirect(303, url); 39 + }, 40 + } satisfies Actions;
+16 -5
src/routes/+page.svelte
··· 1 - <h1>Welcome to SvelteKit</h1> 2 - <p> 3 - Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the 4 - documentation 5 - </p> 1 + <script lang="ts"> 2 + import type { PageProps } from "./$types"; 3 + let { data, form }: PageProps = $props(); 4 + 5 + let handle = $derived(form?.handle ?? ""); 6 + </script> 7 + 8 + <form method="POST" action="?/login"> 9 + <h2>Login</h2> 10 + {#if form?.invalid} 11 + <p><strong>Invalid handle</strong></p> 12 + {/if} 13 + <label for="handle">Handle</label> 14 + <input type="text" id="handle" name="handle" bind:value={handle} /> 15 + <button type="submit">Login</button> 16 + </form>
+49
src/routes/oauth/callback/+server.ts
··· 1 + import { AppBskyActorGetProfile } from "@atcute/bluesky"; 2 + import { Client, ok } from "@atcute/client"; 3 + import { redirect } from "@sveltejs/kit"; 4 + import { oAuthClient } from "$lib/server/oauth.ts"; 5 + import type { RequestHandler } from "./$types"; 6 + import type { OAuthSession } from "@atcute/oauth-node-client"; 7 + 8 + export const GET: RequestHandler = async (event) => { 9 + const { url, cookies } = event; 10 + 11 + // [TODO] delete / handled by @atcute? 12 + // const state = cookies.get("atproto_oauth_request"); 13 + // if (state === undefined) { 14 + // return redirect(303, "/?error=expired"); 15 + // } 16 + // cookies.delete( 17 + // "atproto_oauth_request", 18 + // { path: "/" }, 19 + // ); 20 + 21 + console.log(...url.searchParams); 22 + 23 + let session: OAuthSession; 24 + try { 25 + session = (await oAuthClient.callback(url.searchParams)).session; 26 + } catch (err) { 27 + console.error(err); 28 + redirect(303, "/?error=session"); 29 + } 30 + console.log(session); 31 + 32 + const rpc = new Client({ handler: session }); 33 + const profile = await ok( 34 + rpc.call(AppBskyActorGetProfile, { 35 + params: { actor: session.did }, 36 + }), 37 + ); 38 + 39 + console.log(profile); 40 + 41 + /** 42 + * [TODO] 43 + * parse session params 44 + * encrypt session cookie 45 + * redirect to? 46 + */ 47 + 48 + redirect(303, "/?success"); 49 + };
+3
svelte.config.js
··· 7 7 // If your environment is not supported, or you settled on a specific environment, switch out the adapter. 8 8 // See https://svelte.dev/docs/kit/adapters for more information about adapters. 9 9 adapter: adapter(), 10 + alias: { 11 + $lib: "src/lib", 12 + }, 10 13 }, 11 14 }; 12 15
+1
tsconfig.json
··· 11 11 "sourceMap": true, 12 12 "strict": true, 13 13 "moduleResolution": "bundler", 14 + "types": ["@atcute/bluesky"], 14 15 }, 15 16 // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias 16 17 // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
+5
vite.config.ts
··· 3 3 4 4 export default defineConfig({ 5 5 plugins: [sveltekit()], 6 + server: { 7 + host: "127.0.0.1", 8 + port: 5173, 9 + allowedHosts: [], 10 + }, 6 11 });