Skip to content

Instantly share code, notes, and snippets.

@sugyan
Created July 23, 2024 16:14
Show Gist options
  • Save sugyan/be6ba64d1aad3ccf192380b2c0463f8a to your computer and use it in GitHub Desktop.
Save sugyan/be6ba64d1aad3ccf192380b2c0463f8a to your computer and use it in GitHub Desktop.
import { createServer, IncomingMessage, ServerResponse } from "http";
import { createHash, randomBytes } from "node:crypto";
import { Key } from "@atproto/jwk";
import {
OAuthClient,
InternalStateData,
Session,
DigestAlgorithm,
} from "@atproto/oauth-client";
import { AtprotoHandleResolverNode } from "@atproto-labs/handle-resolver-node";
import { JoseKey } from "@atproto/jwk-jose";
import { Awaitable } from "@atproto/oauth-client/dist/util";
import { Record as PostRecord } from "@atproto/api/src/client/types/app/bsky/feed/post";
import { InputSchema } from "@atproto/api/src/client/types/com/atproto/repo/createRecord";
const YOUR_DID = "did:plc:************************";
const PORT = 8888;
class MemoryStateStore {
private store: Record<string, InternalStateData> = {};
async get(key: string): Promise<undefined | InternalStateData> {
return this.store[key];
}
async set(key: string, value: InternalStateData): Promise<void> {
this.store[key] = value;
}
async del(key: string): Promise<void> {
delete this.store[key];
}
}
class MemorySessionStore {
private store: Record<string, Session> = {};
async get(key: string): Promise<undefined | Session> {
return this.store[key];
}
async set(key: string, value: Session): Promise<void> {
this.store[key] = value;
}
async del(key: string): Promise<void> {
delete this.store[key];
}
}
(async () => {
const client = new OAuthClient({
responseMode: "query",
clientMetadata: {
client_id: "http://localhost",
redirect_uris: [`http://127.0.0.1:${PORT}`],
token_endpoint_auth_method: "none",
},
stateStore: new MemoryStateStore(),
sessionStore: new MemorySessionStore(),
handleResolver: new AtprotoHandleResolverNode(),
runtimeImplementation: {
createKey(algs: string[]): Awaitable<Key> {
return JoseKey.generate(algs, "hoge");
},
getRandomValues: randomBytes,
digest(data: Uint8Array, alg: DigestAlgorithm): Awaitable<Uint8Array> {
return createHash(alg.name).update(data).digest();
},
},
});
const url = await client.authorize(YOUR_DID);
console.log(`Open this URL in your browser: ${url}`);
createServer(async (req: IncomingMessage, res: ServerResponse) => {
if (req.url) {
const params = new URLSearchParams(req.url.slice(2));
const { agent } = await client.callback(params);
console.log(await agent.getInfo());
const session = await (
await agent.request("/xrpc/com.atproto.server.getSession")
).json();
console.log(session);
const record: PostRecord = {
text: "Hello, world! from OAuth client",
createdAt: new Date().toISOString(),
};
const body: InputSchema = {
repo: session.did,
collection: "app.bsky.feed.post",
record,
};
const output = await (
await agent.request("/xrpc/com.atproto.repo.createRecord", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
})
).json();
console.log(output);
}
res.writeHead(200, { "Content-Type": "text/plain" });
}).listen(PORT);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment