scopes are defined here: https://tangled.org/tangled.org/core/blob/master/appview/oauth/scopes.go
they are passed into indigo here: https://tangled.org/tangled.org/core/blob/master/appview/oauth/oauth.go#L49
the client-metadata produced is like so:
{
"client_id": "http://localhost?redirect_uri=http%3A%2F%2F127.0.0.1%3A3000%2Foauth%2Fcallback&scope=atproto+repo%3Ash.tangled.publicKey+repo%3Ash.tangled.repo+repo%3Ash.tangled.repo.pull+repo%3Ash.tangled.repo.pull.comment+repo%3Ash.tangled.repo.artifact+repo%3Ash.tangled.repo.issue+repo%3Ash.tangled.repo.issue.comment+repo%3Ash.tangled.repo.collaborator+repo%3Ash.tangled.knot+repo%3Ash.tangled.knot.member+repo%3Ash.tangled.spindle+repo%3Ash.tangled.spindle.member+repo%3Ash.tangled.graph.follow+repo%3Ash.tangled.feed.star+repo%3Ash.tangled.feed.reaction+repo%3Ash.tangled.label.definition+repo%3Ash.tangled.label.op+repo%3Ash.tangled.string+repo%3Ash.tangled.actor.profile+blob%3A%2A%2F%2A+rpc%3Ash.tangled.repo.create%3Faud%3D%2A+rpc%3Ash.tangled.repo.delete%3Faud%3D%2A+rpc%3Ash.tangled.repo.merge%3Faud%3D%2A+rpc%3Ash.tangled.repo.hiddenRef%3Faud%3D%2A+rpc%3Ash.tangled.repo.deleteBranch%3Faud%3D%2A+rpc%3Ash.tangled.repo.setDefaultBranch%3Faud%3D%2A+rpc%3Ash.tangled.repo.forkSync%3Faud%3D%2A+rpc%3Ash.tangled.repo.forkStatus%3Faud%3D%2A+rpc%3Ash.tangled.repo.mergeCheck%3Faud%3D%2A+rpc%3Ash.tangled.pipeline.cancelPipeline%3Faud%3D%2A+rpc%3Ash.tangled.repo.addSecret%3Faud%3D%2A+rpc%3Ash.tangled.repo.removeSecret%3Faud%3D%2A+rpc%3Ash.tangled.repo.listSecrets%3Faud%3D%2A",
"application_type": "web",
"grant_types": [
"authorization_code",
"refresh_token"
],
"scope": "atproto repo:sh.tangled.publicKey repo:sh.tangled.repo repo:sh.tangled.repo.pull repo:sh.tangled.repo.pull.comment repo:sh.tangled.repo.artifact repo:sh.tangled.repo.issue repo:sh.tangled.repo.issue.comment repo:sh.tangled.repo.collaborator repo:sh.tangled.knot repo:sh.tangled.knot.member repo:sh.tangled.spindle repo:sh.tangled.spindle.member repo:sh.tangled.graph.follow repo:sh.tangled.feed.star repo:sh.tangled.feed.reaction repo:sh.tangled.label.definition repo:sh.tangled.label.op repo:sh.tangled.string repo:sh.tangled.actor.profile blob:*/* rpc:sh.tangled.repo.create?aud=* rpc:sh.tangled.repo.delete?aud=* rpc:sh.tangled.repo.merge?aud=* rpc:sh.tangled.repo.hiddenRef?aud=* rpc:sh.tangled.repo.deleteBranch?aud=* rpc:sh.tangled.repo.setDefaultBranch?aud=* rpc:sh.tangled.repo.forkSync?aud=* rpc:sh.tangled.repo.forkStatus?aud=* rpc:sh.tangled.repo.mergeCheck?aud=* rpc:sh.tangled.pipeline.cancelPipeline?aud=* rpc:sh.tangled.repo.addSecret?aud=* rpc:sh.tangled.repo.removeSecret?aud=* rpc:sh.tangled.repo.listSecrets?aud=*",
"response_types": [
"code"
],
"redirect_uris": [
"http://127.0.0.1:3000/oauth/callback"
],
"token_endpoint_auth_method": "private_key_jwt",
"token_endpoint_auth_signing_alg": "ES256",
"dpop_bound_access_tokens": true,
"jwks_uri": "http://127.0.0.1:3000/oauth/jwks.json",
"client_name": "Tangled",
"client_uri": "http://127.0.0.1:3000"
}
which does include blob:*/*.
the scopes list returnd by the AS also does contain blob:*/*:
09:42:59 INFO oauth scopes granted by PDS did=did:plc:qfpnj4og54vl56wngdriaxug pds=https://grisette.us-west.host.bsky.network scopes="[... blob:*/* ...]"
my fix was to allow specifying the content type in api/atproto/repouploadBlob.go:
// RepoUploadBlob calls the XRPC method "com.atproto.repo.uploadBlob".
func RepoUploadBlob(ctx context.Context, c util.LexClient, input io.Reader, mime string) (*RepoUploadBlob_Output, error) {
var out RepoUploadBlob_Output
if err := c.LexDo(ctx, util.Procedure, mime, "com.atproto.repo.uploadBlob", nil, input, &out); err != nil {
return nil, err
}
return &out, nil
}
and subsequently passing the mime type in calls to RepoUploadBlob:
blob, err := comatproto.RepoUploadBlob(r.Context(), client, gz(patch), "application/gzip")
[asdf asdf asdf asdf asdf asdf]: