An example of Bluesky/atproto OAuth with Svelte
OAuth.svelte
98 lines 2.3 kB view raw
1<script lang="ts"> 2 import { 3 BrowserOAuthClient, 4 OAuthSession 5 } from "@atproto/oauth-client-browser"; 6 7 import { Agent } from "@atproto/api"; 8 import { onMount } from "svelte"; 9 10 let client = $state<BrowserOAuthClient | null>(null); 11 let agent = $state<Agent | null>(null); 12 let loading = $state(true); 13 14 let loggedIn = $state(false); 15 let did = $state(""); 16 let displayName = $state(""); 17 let description = $state(""); 18 19 async function login() { 20 if (!client) { 21 return; // ??? 22 } 23 24 await client.signIn("hexaheximal.com", { 25 state: "", 26 prompt: "login", 27 ui_locales: "en", 28 signal: new AbortController().signal 29 }); 30 } 31 32 onMount(async () => { 33 client = new BrowserOAuthClient({ 34 clientMetadata: { 35 client_id: "https://hexaheximal.com/test.json", 36 client_name: "test", 37 client_uri: "https://hexaheximal.com", 38 redirect_uris: ["https://hexaheximal.com/bluesky-oauth-test"], 39 scope: "atproto transition:generic", 40 grant_types: ["authorization_code", "refresh_token"], 41 response_types: ["code"], 42 token_endpoint_auth_method: "none", 43 application_type: "web", 44 dpop_bound_access_tokens: true 45 }, 46 handleResolver: "https://bsky.social" 47 }); 48 49 (window as any).client = client; 50 51 const result: undefined | { session: OAuthSession; state?: string } = 52 await client.init(); 53 54 if (!result) { 55 loading = false; 56 return; // Not logged in. 57 } 58 59 console.debug(result); 60 61 loggedIn = true; 62 did = result.session.sub; 63 64 agent = new Agent(await client.restore(result.session.sub)); 65 66 const profile = await agent.com.atproto.repo.getRecord({ 67 repo: result.session.sub, 68 collection: "app.bsky.actor.profile", 69 rkey: "self" 70 }); 71 72 console.log(profile); 73 74 // TODO: proper types 75 76 displayName = profile.data.value.displayName as string; 77 description = profile.data.value.description as string; 78 79 loading = false; 80 }); 81</script> 82 83{#if !loading} 84 <div class="p-4"> 85 <h1 class="text-4xl font-bold">Hello, World!</h1> 86 87 {#if loggedIn} 88 <p class="mt-4">Logged in as: {did}</p> 89 <p class="mt-4">Display name: <b>{displayName}</b></p> 90 <p class="mt-4">Description: <b>{description}</b></p> 91 {:else} 92 <button 93 class="mt-4 p-4 pl-16 pr-16 bg-blue-800 rounded-xl hover:opacity-25 transition cursor-pointer" 94 onclick={login}>Log in</button 95 > 96 {/if} 97 </div> 98{/if}