a tiny oauth browser client for atproto using a service worker
11
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix example

+62 -58
+62 -58
example/index.html
··· 1 1 <!doctype html> 2 2 <html> 3 - <head> 4 - <meta charset="utf-8" /> 5 - <title>atproto oauth</title> 6 - <style> 7 - :root { 8 - color-scheme: light dark; 9 - font-family: system-ui, sans-serif; 10 - } 11 - </style> 12 - </head> 13 - <body> 14 - <div id="app"> 15 - <h1>atproto oauth</h1> 16 - <form id="login"> 17 - <input name="handle" placeholder="you.bsky.social" /> 18 - <button>Login</button> 19 - </form> 20 - <pre id="out"></pre> 21 - </div> 22 - <script type="module"> 23 - import { configure, logIn, listSessions, logOut } from "./atsw.js"; 3 + <head> 4 + <meta charset="utf-8" /> 5 + <title>atproto oauth</title> 6 + <style> 7 + :root { 8 + color-scheme: light dark; 9 + font-family: system-ui, sans-serif; 10 + } 11 + </style> 12 + </head> 13 + <body> 14 + <div id="app"> 15 + <h1>atproto oauth</h1> 16 + <form id="login"> 17 + <input name="handle" placeholder="you.bsky.social" /> 18 + <button>Login</button> 19 + </form> 20 + <pre id="out"></pre> 21 + </div> 22 + <script type="module"> 23 + import { logIn, listSessions, logOut } from "./atsw.js"; 24 24 25 - // register the service worker that handles the callback and authenticates PDS requests 26 - await navigator.serviceWorker.register("./atsw.js", { type: "module" }); 27 - await navigator.serviceWorker.ready; 25 + // register the service worker that handles the callback and authenticates PDS requests 26 + await navigator.serviceWorker.register("./atsw.js", { type: "module" }); 27 + await navigator.serviceWorker.ready; 28 28 29 - const config = await configure("./client-metadata.json"); 30 - const out = (msg) => (document.getElementById("out").textContent = msg); 29 + const config = { 30 + clientId: "https://jake.tngl.io/atsw/client-metadata.json", 31 + redirectUri: "https://jake.tngl.io/atsw/", 32 + scope: "atproto repo?collection=com.atproto.server.getSession", 33 + }; 34 + const out = (msg) => (document.getElementById("out").textContent = msg); 31 35 32 - document.getElementById("login").onsubmit = async (e) => { 33 - const data = new FormData(e.target); 34 - const handle = data.get("handle").trim(); 35 - if (!handle) return; 36 - e.preventDefault(); 37 - try { 38 - out("Logging in..."); 39 - await logIn(config, handle); 40 - } catch (e) { 41 - out(e.message); 42 - } 43 - }; 36 + document.getElementById("login").onsubmit = async (e) => { 37 + const data = new FormData(e.target); 38 + const handle = data.get("handle").trim(); 39 + if (!handle) return; 40 + e.preventDefault(); 41 + try { 42 + out("Logging in..."); 43 + await logIn(config, handle); 44 + } catch (e) { 45 + out(e.message); 46 + } 47 + }; 44 48 45 - // Show any sessions the service worker has stored. 46 - const sessions = await listSessions(); 47 - if (sessions.length) { 48 - document.getElementById("login").hidden = true; 49 - const session = sessions[0]; 50 - out(`Logged in as ${session.did} @ ${session.pds}\n\nVerifying session...`); 49 + // Show any sessions the service worker has stored. 50 + const sessions = await listSessions(); 51 + if (sessions.length) { 52 + document.getElementById("login").hidden = true; 53 + const session = sessions[0]; 54 + out(`Logged in as ${session.did} @ ${session.pds}\n\nVerifying session...`); 51 55 52 - // the service worker intercepts this request and signs it with DPoP + auth headers 53 - const res = await fetch(`${session.pds}/xrpc/com.atproto.server.getSession`); 54 - const data = await res.json(); 56 + // the service worker intercepts this request and signs it with DPoP + auth headers 57 + const res = await fetch(`${session.pds}/xrpc/com.atproto.server.getSession`); 58 + const data = await res.json(); 55 59 56 - out(`Session verified:\n${JSON.stringify(data, null, 2)}`); 60 + out(`Session verified:\n${JSON.stringify(data, null, 2)}`); 57 61 58 - const btn = document.createElement("button"); 59 - btn.textContent = "Log out"; 60 - btn.onclick = async () => { 61 - await logOut(session.did); 62 - location.reload(); 63 - }; 64 - document.getElementById("app").appendChild(btn); 65 - } 66 - </script> 67 - </body> 62 + const btn = document.createElement("button"); 63 + btn.textContent = "Log out"; 64 + btn.onclick = async () => { 65 + await logOut(session.did); 66 + location.reload(); 67 + }; 68 + document.getElementById("app").appendChild(btn); 69 + } 70 + </script> 71 + </body> 68 72 </html>