@atproto/oauth-client: atproto flavoured OAuth client
Core library for implementing ATPROTO OAuth clients.
For a browser specific implementation, see @atproto/oauth-client-browser
.
For a node specific implementation, see @atproto/oauth-client-node
.
import { OAuthClient } from '@atproto/oauth-client'
import { JoseKey } from '@atproto/jwk-jose'
const client = new OAuthClient({
handleResolver: 'https://bsky.social',
responseMode: 'query',
clientMetadata: {
},
runtimeImplementation: {
createKey(algs: string[]): Promise<Key> {
return JoseKey.generate(algs)
},
getRandomValues(length: number): Uint8Array | PromiseLike<Uint8Array> {
const bytes = new Uint8Array(byteLength)
crypto.getRandomValues(bytes)
return bytes
},
digest(
bytes: Uint8Array,
algorithm: { name: 'sha256' | 'sha384' | 'sha512' },
): Uint8Array | PromiseLike<Uint8Array> {
const buffer = await this.crypto.subtle.digest(
algorithm.name.startsWith('sha')
? `SHA-${algorithm.name.slice(-3)}`
: 'invalid',
bytes,
)
return new Uint8Array(buffer)
},
},
stateStore: {
set(key: string, internalState: InternalStateData): Promise<void> {
throw new Error('Not implemented')
},
get(key: string): Promise<InternalStateData | undefined> {
throw new Error('Not implemented')
},
del(key: string): Promise<void> {
throw new Error('Not implemented')
},
},
sessionStore: {
set(sub: string, session: Session): Promise<void> {
throw new Error('Not implemented')
},
get(sub: string): Promise<Session | undefined> {
throw new Error('Not implemented')
},
del(sub: string): Promise<void> {
throw new Error('Not implemented')
},
},
keyset: [
await JoseKey.fromImportable(process.env.PRIVATE_KEY_1),
await JoseKey.fromImportable(process.env.PRIVATE_KEY_2),
await JoseKey.fromImportable(process.env.PRIVATE_KEY_3),
],
})
const url = await client.authorize('foo.bsky.team', {
state: '434321',
prompt: 'consent',
scope: 'email',
ui_locales: 'fr',
})
const params = new URLSearchParams('code=...&state=...')
const result = await client.callback(params)
result.state === '434321'
result.agent.sub
await result.agent.request('/xrpc/foo.bar')
await result.agent.signOut()