Packages

A small, transport-agnostic atproto client for Gleam: XRPC, identity, OAuth discovery, blobs, and repo CRUD.

Current section

Files

Jump to
atproto_client src atproto auth.gleam
Raw

src/atproto/auth.gleam

//// atproto session auth: exchange an identifier + password for session tokens
//// via `com.atproto.server.createSession`, and refresh them via
//// `com.atproto.server.refreshSession`.
import atproto/xrpc.{type Client, type XrpcError}
import gleam/dynamic/decode
import gleam/json
import gleam/option.{None, Some}
import gleam/result
pub type SessionTokens {
SessionTokens(
did: String,
handle: String,
access_jwt: String,
refresh_jwt: String,
)
}
pub fn create_session(
client: Client,
pds: String,
identifier: String,
password: String,
) -> Result(SessionTokens, XrpcError) {
let body =
json.object([
#("identifier", json.string(identifier)),
#("password", json.string(password)),
])
use resp <- result.try(xrpc.post_json(
client,
pds <> "/xrpc/com.atproto.server.createSession",
None,
body,
))
xrpc.parse(resp.body, tokens_decoder())
}
/// Exchange a refresh JWT for a fresh session (the refresh token is sent as the
/// bearer credential, per `com.atproto.server.refreshSession`).
pub fn refresh_session(
client: Client,
pds: String,
refresh_jwt: String,
) -> Result(SessionTokens, XrpcError) {
use resp <- result.try(xrpc.post_json(
client,
pds <> "/xrpc/com.atproto.server.refreshSession",
Some(refresh_jwt),
json.object([]),
))
xrpc.parse(resp.body, tokens_decoder())
}
fn tokens_decoder() -> decode.Decoder(SessionTokens) {
use did <- decode.field("did", decode.string)
use handle <- decode.field("handle", decode.string)
use access_jwt <- decode.field("accessJwt", decode.string)
use refresh_jwt <- decode.field("refreshJwt", decode.string)
decode.success(SessionTokens(did:, handle:, access_jwt:, refresh_jwt:))
}