this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix weird whitespace in doc.go

+46 -52
+46 -52
atproto/auth/oauth/doc.go
··· 20 20 ``` 21 21 oauthScope := "atproto transition:generic" 22 22 config := oauth.NewPublicConfig( 23 - 24 23 "https://app.example.com/client-metadata.json", 25 24 "https://app.example.com/oauth/callback", 26 - 27 25 ) 28 26 29 27 // clients are "public" by default, but if they have secure access to a secret attestation key can be "confidential" 30 28 31 - if CLIENT_SECRET_KEY != "" { 32 - priv, err := crypto.ParsePrivateMultibase(CLIENT_SECRET_KEY) 33 - if err != nil { 34 - return err 35 - } 36 - if err := config.AddClientSecret(priv, "example1"); err != nil { 37 - return err 38 - } 29 + if CLIENT_SECRET_KEY != "" { 30 + priv, err := crypto.ParsePrivateMultibase(CLIENT_SECRET_KEY) 31 + if err != nil { 32 + return err 33 + } 34 + if err := config.AddClientSecret(priv, "example1"); err != nil { 35 + return err 39 36 } 37 + } 40 38 41 39 oauthApp := oauth.NewClientApp(&config, oauth.NewMemStore()) 42 40 ``` ··· 48 46 ``` 49 47 http.HandleFunc("GET /client-metadata.json", HandleClientMetadata) 50 48 51 - func HandleClientMetadata(w http.ResponseWriter, r *http.Request) { 52 - doc := oauthApp.Config.ClientMetadata(oauthScope) 53 - w.Header().Set("Content-Type", "application/json") 54 - if err := json.NewEncoder(w).Encode(doc); err != nil { 55 - http.Error(w, err.Error(), http.StatusInternalServerError) 56 - return 57 - } 49 + func HandleClientMetadata(w http.ResponseWriter, r *http.Request) { 50 + doc := oauthApp.Config.ClientMetadata(oauthScope) 51 + w.Header().Set("Content-Type", "application/json") 52 + if err := json.NewEncoder(w).Encode(doc); err != nil { 53 + http.Error(w, err.Error(), http.StatusInternalServerError) 54 + return 58 55 } 59 - 56 + } 60 57 ``` 61 58 62 59 The login auth flow starts with a user identifier, which could be an atproto handle, DID, or a host URL. The high-level [StartAuthFlow()] method will resolve the identifier, send an auth request (PAR) to the server, persist request metadata in the [OAuthStore], and return a redirect URL for the user to visit: ··· 64 61 ``` 65 62 http.HandleFunc("GET /oauth/login", HandleLogin) 66 63 67 - func HandleLogin(w http.ResponseWriter, r *http.Request) { 68 - ctx := r.Context() 64 + func HandleLogin(w http.ResponseWriter, r *http.Request) { 65 + ctx := r.Context() 69 66 70 - // parse login identifier from the request 71 - identifier := "..." 67 + // parse login identifier from the request 68 + identifier := "..." 72 69 73 - redirectURL, err := oauthApp.StartAuthFlow(ctx, identifier) 74 - if err != nil { 75 - http.Error(w, err.Error(), http.StatusInternalServerError) 76 - } 77 - http.Redirect(w, r, redirectURL, http.StatusFound) 70 + redirectURL, err := oauthApp.StartAuthFlow(ctx, identifier) 71 + if err != nil { 72 + http.Error(w, err.Error(), http.StatusInternalServerError) 78 73 } 79 - 74 + http.Redirect(w, r, redirectURL, http.StatusFound) 75 + } 80 76 ``` 81 77 82 78 The service then waits for a callback request on the configured endpoint. The [ProcessCallback()] method will load the earlier request metadata from the [OAuthStore], send an initial token request to the auth server, and validate that the session is consistent with the identifier from the begining of the login flow. ··· 84 80 ``` 85 81 http.HandleFunc("GET /client-metadata.json", HandleClientMetadata) 86 82 87 - func HandleOAuthCallback(w http.ResponseWriter, r *http.Request) { 88 - ctx := r.Context() 83 + func HandleOAuthCallback(w http.ResponseWriter, r *http.Request) { 84 + ctx := r.Context() 89 85 90 - sessData, err := oauthApp.ProcessCallback(ctx, r.URL.Query()) 91 - if err != nil { 92 - http.Error(w, err.Error(), http.StatusInternalServerError) 93 - } 86 + sessData, err := oauthApp.ProcessCallback(ctx, r.URL.Query()) 87 + if err != nil { 88 + http.Error(w, err.Error(), http.StatusInternalServerError) 89 + } 94 90 95 - // web services might record the DID in a secure session cookie 96 - _ = sessData.AccountDID 91 + // web services might record the DID in a secure session cookie 92 + _ = sessData.AccountDID 97 93 98 - http.Redirect(w, r, "/app", http.StatusFound) 99 - } 100 - 94 + http.Redirect(w, r, "/app", http.StatusFound) 95 + } 101 96 ``` 102 97 103 98 Finally, sessions can be resumed and used to make authenticated API calls to the user's host: ··· 114 109 115 110 c := sess.APIClient() 116 111 117 - body := map[string]any{ 118 - "repo": *c.AccountDID, 119 - "collection": "app.bsky.feed.post", 120 - "record": map[string]any{ 121 - "$type": "app.bsky.feed.post", 122 - "text": "Hello World via OAuth!", 123 - "createdAt": syntax.DatetimeNow(), 124 - }, 125 - } 126 - 127 - if err := c.Post(ctx, "com.atproto.repo.createRecord", body, nil); err != nil { 128 - return err 129 - } 112 + body := map[string]any{ 113 + "repo": *c.AccountDID, 114 + "collection": "app.bsky.feed.post", 115 + "record": map[string]any{ 116 + "$type": "app.bsky.feed.post", 117 + "text": "Hello World via OAuth!", 118 + "createdAt": syntax.DatetimeNow(), 119 + }, 120 + } 130 121 122 + if err := c.Post(ctx, "com.atproto.repo.createRecord", body, nil); err != nil { 123 + return err 124 + } 131 125 ``` 132 126 133 127 The [ClientSession] will handle nonce updates and token refreshes, and persist the results in the [OAuthStore].