+90
README.md
+90
README.md
···
231
231
232
232
Now, you can store the response items to make make authenticated requests later. You likely will want to store at least the user's DID in a secure session so that you know who the user is.
233
233
234
+
### Refreshing the token
235
+
236
+
The acess token you receive will expire after one hour and you will need to refresh it. You may choose to create a helper method that will refresh the token as necessary whenever you fetch the authentication information from your store. For an example, see `cmd/client_test/user.go`.
237
+
238
+
## Making requests
239
+
240
+
You may have some experience using the atproto SDK's helper methods from `indigo`. For example, you may be able to call `ActorGetProfile()` to fetch a user's profile. Currently, the atproto SDK does not support OAuth however, and will need some
241
+
changes. In the meantime, I have added a custom XRPC client to this repo that can be used with OAuth sessions created in this library.
242
+
243
+
### Creating an XRPC client
244
+
245
+
Similar to the `indigo/xrpc` package, you can create an XRPC client like so
246
+
247
+
```go
248
+
client := &oauth.XrpcClient{
249
+
OnDpopPdsNonceChanged: func(did, newNonce string) {
250
+
// Handle updating your store with the new nonce
251
+
},
252
+
}
253
+
```
254
+
255
+
The `OnDpopPdsNonceChanged` callback will fire whenever an authenticated request results in an updated DPoP PDS nonce. You should update your store with this nonce for future requests.
256
+
257
+
### Making requests
258
+
259
+
Instead of using "helpers", for now you should make requests by simply calling `Do()` on the XRPC client. You will need to pass `XrpcAuthedRequestArgs` to the function to perform authenticated requests.
260
+
If the parameter is `nil`, the request will be made unauthenticated. A few examples are below.
261
+
262
+
#### Creating authentication arguments
263
+
264
+
```go
265
+
// Get your user's session - however you are doing that - and retrieve their did
266
+
267
+
// Grab the oauth session from your database
268
+
oauthSession, err := s.getOauthSession(e.Request().Context(), did)
269
+
270
+
// Parse the user's JWK to pass into arguments
271
+
privateJwk, err := oauth.ParseJWKFromBytes([]byte(oauthSession.DpopPrivateJwk))
272
+
if err != nil {
273
+
return nil, false, err
274
+
}
275
+
276
+
return &oauth.XrpcAuthedRequestArgs{
277
+
Did: oauthSession.Did,
278
+
AccessToken: oauthSession.AccessToken,
279
+
PdsUrl: oauthSession.PdsUrl,
280
+
Issuer: oauthSession.AuthserverIss,
281
+
DpopPdsNonce: oauthSession.DpopPdsNonce,
282
+
DpopPrivateJwk: privateJwk,
283
+
}, nil
284
+
```
285
+
286
+
#### Making a post
287
+
288
+
```go
289
+
authArgs, err := s.getOauthSessionAuthArgs(e)
290
+
if err != nil {
291
+
return err
292
+
}
293
+
294
+
post := bsky.FeedPost{
295
+
Text: "hello from atproto golang oauth client",
296
+
CreatedAt: syntax.DatetimeNow().String(),
297
+
}
298
+
299
+
input := atproto.RepoCreateRecord_Input{
300
+
Collection: "app.bsky.feed.post",
301
+
Repo: authArgs.Did,
302
+
Record: &util.LexiconTypeDecoder{Val: &post},
303
+
}
304
+
305
+
var out atproto.RepoCreateRecord_Output
306
+
if err := s.xrpcCli.Do(e.Request().Context(), authArgs, xrpc.Procedure, "application/json", "com.atproto.repo.createRecord", nil, input, &out); err != nil {
307
+
return err
308
+
}
309
+
```
310
+
311
+
#### Getting a profile
312
+
313
+
```go
314
+
authArgs, err := s.getOauthSessionAuthArgs(e)
315
+
if err != nil {
316
+
return err
317
+
}
318
+
319
+
var out bsky.ActorDefs_ProfileViewDetailed
320
+
if err := s.xrpcCli.Do(e.Request().Context(), authArgs, xrpc.Query, "", "app.bsky.actor.getProfile", map[string]any{"actor": authArgs.Did}, nil, &out); err != nil {
321
+
return err
322
+
}
323
+
```