···231231232232Now, 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.
233233234234+### Refreshing the token
235235+236236+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`.
237237+238238+## Making requests
239239+240240+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
241241+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.
242242+243243+### Creating an XRPC client
244244+245245+Similar to the `indigo/xrpc` package, you can create an XRPC client like so
246246+247247+```go
248248+client := &oauth.XrpcClient{
249249+ OnDpopPdsNonceChanged: func(did, newNonce string) {
250250+ // Handle updating your store with the new nonce
251251+ },
252252+}
253253+```
254254+255255+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.
256256+257257+### Making requests
258258+259259+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.
260260+If the parameter is `nil`, the request will be made unauthenticated. A few examples are below.
261261+262262+#### Creating authentication arguments
263263+264264+```go
265265+// Get your user's session - however you are doing that - and retrieve their did
266266+267267+// Grab the oauth session from your database
268268+oauthSession, err := s.getOauthSession(e.Request().Context(), did)
269269+270270+// Parse the user's JWK to pass into arguments
271271+privateJwk, err := oauth.ParseJWKFromBytes([]byte(oauthSession.DpopPrivateJwk))
272272+if err != nil {
273273+ return nil, false, err
274274+}
275275+276276+return &oauth.XrpcAuthedRequestArgs{
277277+ Did: oauthSession.Did,
278278+ AccessToken: oauthSession.AccessToken,
279279+ PdsUrl: oauthSession.PdsUrl,
280280+ Issuer: oauthSession.AuthserverIss,
281281+ DpopPdsNonce: oauthSession.DpopPdsNonce,
282282+ DpopPrivateJwk: privateJwk,
283283+}, nil
284284+```
285285+286286+#### Making a post
287287+288288+```go
289289+authArgs, err := s.getOauthSessionAuthArgs(e)
290290+if err != nil {
291291+ return err
292292+}
293293+294294+post := bsky.FeedPost{
295295+ Text: "hello from atproto golang oauth client",
296296+ CreatedAt: syntax.DatetimeNow().String(),
297297+}
298298+299299+input := atproto.RepoCreateRecord_Input{
300300+ Collection: "app.bsky.feed.post",
301301+ Repo: authArgs.Did,
302302+ Record: &util.LexiconTypeDecoder{Val: &post},
303303+}
304304+305305+var out atproto.RepoCreateRecord_Output
306306+if err := s.xrpcCli.Do(e.Request().Context(), authArgs, xrpc.Procedure, "application/json", "com.atproto.repo.createRecord", nil, input, &out); err != nil {
307307+ return err
308308+}
309309+```
310310+311311+#### Getting a profile
312312+313313+```go
314314+authArgs, err := s.getOauthSessionAuthArgs(e)
315315+if err != nil {
316316+ return err
317317+}
318318+319319+var out bsky.ActorDefs_ProfileViewDetailed
320320+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 {
321321+ return err
322322+}
323323+```