fork of haileyok/atproto-oauth-golang

add redirection to pds

Changed files
+386 -19
cmd
+1
.gitignore
··· 1 1 cmd/client_test/client_test 2 2 jwks.json 3 3 .env 4 + oauth.db
+9
cmd/client_test/html/index.html
··· 1 + <!doctype html> 2 + <html> 3 + <p>welcome to atproto oauth golang tester!</p> 4 + <ul> 5 + <li> 6 + <a href="/login">Login</a> 7 + </li> 8 + </ul> 9 + </html>
+7
cmd/client_test/html/login.html
··· 1 + <!doctype html> 2 + <html> 3 + <form action="/login" method="post"> 4 + <input name="handle" id="handle" placeholder="Enter your handle" /> 5 + <button type="submit" value="Submit">Submit</button> 6 + </form> 7 + </html>
+276 -2
cmd/client_test/main.go
··· 2 2 3 3 import ( 4 4 "context" 5 + "encoding/json" 5 6 "fmt" 7 + "io" 6 8 "log/slog" 9 + "net" 7 10 "net/http" 11 + "net/url" 8 12 "os" 13 + "strings" 9 14 15 + "github.com/bluesky-social/indigo/atproto/syntax" 10 16 oauth "github.com/haileyok/atproto-oauth-golang" 11 17 _ "github.com/joho/godotenv/autoload" 12 18 "github.com/labstack/echo/v4" 13 19 "github.com/lestrrat-go/jwx/v2/jwk" 14 20 slogecho "github.com/samber/slog-echo" 15 21 "github.com/urfave/cli/v2" 22 + "gorm.io/driver/sqlite" 23 + "gorm.io/gorm" 16 24 ) 17 25 18 26 var ( 19 27 ctx = context.Background() 20 28 serverAddr = os.Getenv("OAUTH_TEST_SERVER_ADDR") 21 29 serverUrlRoot = os.Getenv("OAUTH_TEST_SERVER_URL_ROOT") 30 + staticFilePath = os.Getenv("OAUTH_TEST_SERVER_STATIC_PATH") 22 31 serverMetadataUrl = fmt.Sprintf("%s/oauth/client-metadata.json", serverUrlRoot) 23 32 serverCallbackUrl = fmt.Sprintf("%s/callback", serverUrlRoot) 24 33 pdsUrl = os.Getenv("OAUTH_TEST_PDS_URL") 34 + scope = "atproto transition:generic" 25 35 ) 26 36 27 37 func main() { ··· 40 50 type TestServer struct { 41 51 httpd *http.Server 42 52 e *echo.Echo 53 + db *gorm.DB 54 + oauthClient *oauth.OauthClient 43 55 jwksResponse *oauth.JwksResponseObject 44 56 } 45 57 ··· 64 76 b, err := os.ReadFile("./jwks.json") 65 77 if err != nil { 66 78 if os.IsNotExist(err) { 67 - return nil, fmt.Errorf("could not find jwks.json. does it exist? hint: run `go run ./cmd/cmd generate-jwks --prefix demo` to create one.") 79 + return nil, fmt.Errorf( 80 + "could not find jwks.json. does it exist? hint: run `go run ./cmd/cmd generate-jwks --prefix demo` to create one.", 81 + ) 68 82 } 69 83 return nil, err 70 84 } ··· 79 93 return nil, err 80 94 } 81 95 96 + c, err := oauth.NewOauthClient(oauth.OauthClientArgs{ 97 + ClientJwk: k, 98 + ClientId: serverMetadataUrl, 99 + RedirectUri: serverCallbackUrl, 100 + }) 101 + if err != nil { 102 + return nil, err 103 + } 104 + 82 105 httpd := &http.Server{ 83 106 Addr: serverAddr, 84 107 Handler: e, 85 108 } 86 109 87 - fmt.Println("starting http server...") 110 + db, err := gorm.Open(sqlite.Open("oauth.db"), &gorm.Config{}) 111 + if err != nil { 112 + return nil, err 113 + } 114 + 115 + db.AutoMigrate(&OauthRequest{}) 88 116 89 117 return &TestServer{ 90 118 httpd: httpd, 91 119 e: e, 120 + db: db, 121 + oauthClient: c, 92 122 jwksResponse: oauth.CreateJwksResponseObject(pubKey), 93 123 }, nil 94 124 } 95 125 96 126 func (s *TestServer) run() error { 127 + s.e.File("/", s.getFilePath("index.html")) 128 + s.e.File("/login", s.getFilePath("login.html")) 129 + s.e.POST("/login", s.handleLoginSubmit) 97 130 s.e.GET("/oauth/client-metadata.json", s.handleClientMetadata) 98 131 s.e.GET("/oauth/jwks.json", s.handleJwks) 99 132 ··· 129 162 func (s *TestServer) handleJwks(e echo.Context) error { 130 163 return e.JSON(200, s.jwksResponse) 131 164 } 165 + 166 + func (s *TestServer) handleLoginSubmit(e echo.Context) error { 167 + handle := e.FormValue("handle") 168 + if handle == "" { 169 + return e.Redirect(302, "/login?e=handle-empty") 170 + } 171 + 172 + _, herr := syntax.ParseHandle(handle) 173 + _, derr := syntax.ParseDID(handle) 174 + 175 + if herr != nil && derr != nil { 176 + return e.Redirect(302, "/login?e=handle-invalid") 177 + } 178 + 179 + var did string 180 + 181 + if derr == nil { 182 + did = handle 183 + } else { 184 + maybeDid, err := resolveHandle(e.Request().Context(), handle) 185 + if err != nil { 186 + return err 187 + } 188 + 189 + did = maybeDid 190 + } 191 + 192 + service, err := resolveService(ctx, did) 193 + if err != nil { 194 + return err 195 + } 196 + 197 + authserver, err := s.oauthClient.ResolvePDSAuthServer(ctx, service) 198 + if err != nil { 199 + return err 200 + } 201 + 202 + meta, err := s.oauthClient.FetchAuthServerMetadata(ctx, authserver) 203 + if err != nil { 204 + return err 205 + } 206 + 207 + dpopPrivateKey, err := oauth.GenerateKey(nil) 208 + if err != nil { 209 + return err 210 + } 211 + 212 + dpopPrivateKeyJson, err := json.Marshal(dpopPrivateKey) 213 + if err != nil { 214 + return err 215 + } 216 + 217 + parResp, err := s.oauthClient.SendParAuthRequest( 218 + ctx, 219 + authserver, 220 + meta, 221 + "", 222 + scope, 223 + dpopPrivateKey, 224 + ) 225 + 226 + oauthRequest := OauthRequest{ 227 + State: "", 228 + AuthserverIss: meta.Issuer, 229 + Did: did, 230 + PdsUrl: service, 231 + PkceVerifier: parResp.PkceVerifier, 232 + DpopAuthserverNonce: parResp.DpopAuthserverNonce, 233 + DpopPrivateJwk: string(dpopPrivateKeyJson), 234 + } 235 + 236 + if err := s.db.Create(&oauthRequest).Error; err != nil { 237 + return err 238 + } 239 + 240 + u, _ := url.Parse(meta.AuthorizationEndpoint) 241 + u.RawQuery = fmt.Sprintf( 242 + "client_id=%s&request_uri=%s", 243 + url.QueryEscape(serverMetadataUrl), 244 + parResp.Resp["request_uri"].(string), 245 + ) 246 + 247 + return e.Redirect(302, u.String()) 248 + } 249 + 250 + func resolveHandle(ctx context.Context, handle string) (string, error) { 251 + var did string 252 + 253 + _, err := syntax.ParseHandle(handle) 254 + if err != nil { 255 + return "", err 256 + } 257 + 258 + recs, err := net.LookupTXT(fmt.Sprintf("_atproto.%s", handle)) 259 + if err != nil { 260 + return "", err 261 + } 262 + 263 + for _, rec := range recs { 264 + if strings.HasPrefix(rec, "did=") { 265 + did = strings.Split(rec, "did=")[1] 266 + break 267 + } 268 + } 269 + 270 + if did == "" { 271 + req, err := http.NewRequestWithContext( 272 + ctx, 273 + "GET", 274 + fmt.Sprintf("https://%s/.well-known/atproto-did", handle), 275 + nil, 276 + ) 277 + if err != nil { 278 + return "", err 279 + } 280 + 281 + resp, err := http.DefaultClient.Do(req) 282 + if err != nil { 283 + return "", err 284 + } 285 + defer resp.Body.Close() 286 + 287 + if resp.StatusCode != http.StatusOK { 288 + io.Copy(io.Discard, resp.Body) 289 + return "", fmt.Errorf("unable to resolve handle") 290 + } 291 + 292 + b, err := io.ReadAll(resp.Body) 293 + if err != nil { 294 + return "", err 295 + } 296 + 297 + maybeDid := string(b) 298 + 299 + if _, err := syntax.ParseDID(maybeDid); err != nil { 300 + return "", fmt.Errorf("unable to resolve handle") 301 + } 302 + 303 + did = maybeDid 304 + } 305 + 306 + // TODO: we can also support did:web here 307 + 308 + if did == "" { 309 + return "", fmt.Errorf("unable to resolve handle") 310 + } 311 + 312 + return did, nil 313 + } 314 + 315 + func resolveService(ctx context.Context, did string) (string, error) { 316 + type Identity struct { 317 + Service []struct { 318 + ID string `json:"id"` 319 + Type string `json:"type"` 320 + ServiceEndpoint string `json:"serviceEndpoint"` 321 + } `json:"service"` 322 + } 323 + 324 + if strings.HasPrefix(did, "did:plc:") { 325 + req, err := http.NewRequestWithContext( 326 + ctx, 327 + "GET", 328 + fmt.Sprintf("https://plc.directory/%s", did), 329 + nil, 330 + ) 331 + if err != nil { 332 + return "", err 333 + } 334 + 335 + resp, err := http.DefaultClient.Do(req) 336 + if err != nil { 337 + return "", err 338 + } 339 + defer resp.Body.Close() 340 + 341 + if resp.StatusCode != 200 { 342 + io.Copy(io.Discard, resp.Body) 343 + return "", fmt.Errorf("could not find identity in plc registry") 344 + } 345 + 346 + var identity Identity 347 + if err := json.NewDecoder(resp.Body).Decode(&identity); err != nil { 348 + return "", err 349 + } 350 + 351 + var service string 352 + for _, svc := range identity.Service { 353 + if svc.ID == "#atproto_pds" { 354 + service = svc.ServiceEndpoint 355 + } 356 + } 357 + 358 + if service == "" { 359 + return "", fmt.Errorf("could not find atproto_pds service in identity services") 360 + } 361 + 362 + return service, nil 363 + } else if strings.HasPrefix(did, "did:web:") { 364 + // TODO: needs more work 365 + req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://%s/.well-known/did.json", did), nil) 366 + if err != nil { 367 + return "", err 368 + } 369 + 370 + resp, err := http.DefaultClient.Do(req) 371 + if err != nil { 372 + return "", err 373 + } 374 + defer resp.Body.Close() 375 + 376 + if resp.StatusCode != 200 { 377 + io.Copy(io.Discard, resp.Body) 378 + return "", fmt.Errorf("could not find identity in plc registry") 379 + } 380 + 381 + var identity Identity 382 + if err := json.NewDecoder(resp.Body).Decode(&identity); err != nil { 383 + return "", err 384 + } 385 + 386 + var service string 387 + for _, svc := range identity.Service { 388 + if svc.ID == "#atproto_pds" { 389 + service = svc.ServiceEndpoint 390 + } 391 + } 392 + 393 + if service == "" { 394 + return "", fmt.Errorf("could not find atproto_pds service in identity services") 395 + } 396 + 397 + return service, nil 398 + } else { 399 + return "", fmt.Errorf("did was not a supported did type") 400 + } 401 + } 402 + 403 + func (s *TestServer) getFilePath(file string) string { 404 + return fmt.Sprintf("%s/%s", staticFilePath, file) 405 + }
+12
cmd/client_test/types.go
··· 1 + package main 2 + 3 + type OauthRequest struct { 4 + ID uint 5 + AuthserverIss string 6 + State string 7 + Did string `gorm:"index"` 8 + PdsUrl string 9 + PkceVerifier string 10 + DpopAuthserverNonce string 11 + DpopPrivateJwk string 12 + }
+8 -3
go.mod
··· 3 3 go 1.24.0 4 4 5 5 require ( 6 + github.com/bluesky-social/indigo v0.0.0-20250301025210-a4e0cc37e188 6 7 github.com/golang-jwt/jwt/v5 v5.2.1 7 8 github.com/google/uuid v1.6.0 9 + github.com/joho/godotenv v1.5.1 8 10 github.com/labstack/echo/v4 v4.13.3 9 11 github.com/lestrrat-go/jwx/v2 v2.0.12 12 + github.com/samber/slog-echo v1.15.1 10 13 github.com/stretchr/testify v1.10.0 11 14 github.com/urfave/cli/v2 v2.27.5 15 + gorm.io/driver/sqlite v1.5.7 16 + gorm.io/gorm v1.25.9 12 17 ) 13 18 14 19 require ( ··· 16 21 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 17 22 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect 18 23 github.com/goccy/go-json v0.10.2 // indirect 19 - github.com/joho/godotenv v1.5.1 // indirect 20 - github.com/kr/pretty v0.3.1 // indirect 24 + github.com/jinzhu/inflection v1.0.0 // indirect 25 + github.com/jinzhu/now v1.1.5 // indirect 21 26 github.com/labstack/gommon v0.4.2 // indirect 22 27 github.com/lestrrat-go/blackmagic v1.0.2 // indirect 23 28 github.com/lestrrat-go/httpcc v1.0.1 // indirect ··· 26 31 github.com/lestrrat-go/option v1.0.1 // indirect 27 32 github.com/mattn/go-colorable v0.1.13 // indirect 28 33 github.com/mattn/go-isatty v0.0.20 // indirect 34 + github.com/mattn/go-sqlite3 v1.14.22 // indirect 29 35 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect 30 36 github.com/rogpeppe/go-internal v1.13.1 // indirect 31 37 github.com/russross/blackfriday/v2 v2.1.0 // indirect 32 38 github.com/samber/lo v1.47.0 // indirect 33 - github.com/samber/slog-echo v1.15.1 // indirect 34 39 github.com/segmentio/asm v1.2.0 // indirect 35 40 github.com/valyala/bytebufferpool v1.0.0 // indirect 36 41 github.com/valyala/fasttemplate v1.2.2 // indirect
+14 -3
go.sum
··· 1 + github.com/bluesky-social/indigo v0.0.0-20250301025210-a4e0cc37e188 h1:1sQaG37xk08/rpmdhrmMkfQWF9kZbnfHm9Zav3bbSMk= 2 + github.com/bluesky-social/indigo v0.0.0-20250301025210-a4e0cc37e188/go.mod h1:NVBwZvbBSa93kfyweAmKwOLYawdVHdwZ9s+GZtBBVLA= 1 3 github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= 2 4 github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 3 - github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 4 5 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 6 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 7 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= ··· 12 13 github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 13 14 github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= 14 15 github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= 16 + github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 17 + github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 15 18 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 16 19 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 20 + github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 21 + github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 22 + github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= 23 + github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 17 24 github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= 18 25 github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 19 26 github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= ··· 46 53 github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 47 54 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 48 55 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 49 - github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 56 + github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= 57 + github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= 50 58 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 51 59 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 52 60 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 53 - github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 54 61 github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= 55 62 github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= 56 63 github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= ··· 137 144 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 138 145 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 139 146 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 147 + gorm.io/driver/sqlite v1.5.7 h1:8NvsrhP0ifM7LX9G4zPB97NwovUakUxc+2V2uuf3Z1I= 148 + gorm.io/driver/sqlite v1.5.7/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4= 149 + gorm.io/gorm v1.25.9 h1:wct0gxZIELDk8+ZqF/MVnHLkA1rvYlBWUMv2EdsK1g8= 150 + gorm.io/gorm v1.25.9/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
+59 -11
oauth.go
··· 107 107 return resource.AuthorizationServers[0], nil 108 108 } 109 109 110 - func (c *OauthClient) FetchAuthServerMetadata(ctx context.Context, ustr string) (*OauthAuthorizationMetadata, error) { 110 + func (c *OauthClient) FetchAuthServerMetadata( 111 + ctx context.Context, 112 + ustr string, 113 + ) (*OauthAuthorizationMetadata, error) { 111 114 u, err := isSafeAndParsed(ustr) 112 115 if err != nil { 113 116 return nil, err ··· 128 131 129 132 if resp.StatusCode != http.StatusOK { 130 133 io.Copy(io.Discard, resp.Body) 131 - return nil, fmt.Errorf("received non-200 response from pds. status code was %d", resp.StatusCode) 134 + return nil, fmt.Errorf( 135 + "received non-200 response from pds. status code was %d", 136 + resp.StatusCode, 137 + ) 132 138 } 133 139 134 140 b, err := io.ReadAll(resp.Body) ··· 168 174 return tokenString, nil 169 175 } 170 176 171 - func (c *OauthClient) AuthServerDpopJwt(method, url, nonce string, privateJwk jwk.Key) (string, error) { 177 + func (c *OauthClient) AuthServerDpopJwt( 178 + method, url, nonce string, 179 + privateJwk jwk.Key, 180 + ) (string, error) { 172 181 pubJwk, err := privateJwk.PublicKey() 173 182 if err != nil { 174 183 return "", err ··· 223 232 Resp map[string]any 224 233 } 225 234 226 - func (c *OauthClient) SendParAuthRequest(ctx context.Context, authServerUrl string, authServerMeta *OauthAuthorizationMetadata, loginHint, scope string, dpopPrivateKey jwk.Key) (*SendParAuthResponse, error) { 235 + func (c *OauthClient) SendParAuthRequest( 236 + ctx context.Context, 237 + authServerUrl string, 238 + authServerMeta *OauthAuthorizationMetadata, 239 + loginHint, scope string, 240 + dpopPrivateKey jwk.Key, 241 + ) (*SendParAuthResponse, error) { 227 242 if authServerMeta == nil { 228 243 return nil, fmt.Errorf("nil metadata provided") 229 244 } ··· 302 317 return nil, err 303 318 } 304 319 305 - req2, err := http.NewRequestWithContext(ctx, "POST", parUrl, strings.NewReader(params.Encode())) 320 + req2, err := http.NewRequestWithContext( 321 + ctx, 322 + "POST", 323 + parUrl, 324 + strings.NewReader(params.Encode()), 325 + ) 306 326 if err != nil { 307 327 return nil, err 308 328 } ··· 335 355 Resp map[string]string 336 356 } 337 357 338 - func (c *OauthClient) InitialTokenRequest(ctx context.Context, authRequest map[string]string, code, appUrl string) (*TokenResponse, error) { 358 + func (c *OauthClient) InitialTokenRequest( 359 + ctx context.Context, 360 + authRequest map[string]string, 361 + code, appUrl string, 362 + ) (*TokenResponse, error) { 339 363 authserverUrl := authRequest["authserver_iss"] 340 364 authserverMeta, err := c.FetchAuthServerMetadata(ctx, authserverUrl) 341 365 if err != nil { ··· 362 386 return nil, err 363 387 } 364 388 365 - dpopProof, err := c.AuthServerDpopJwt("POST", authserverMeta.TokenEndpoint, authRequest["dpop_authserver_nonce"], dpopPrivateJwk) 389 + dpopProof, err := c.AuthServerDpopJwt( 390 + "POST", 391 + authserverMeta.TokenEndpoint, 392 + authRequest["dpop_authserver_nonce"], 393 + dpopPrivateJwk, 394 + ) 366 395 if err != nil { 367 396 return nil, err 368 397 } 369 398 370 399 dpopAuthserverNonce := authRequest["dpop_authserver_nonce"] 371 400 372 - req, err := http.NewRequestWithContext(ctx, "POST", authserverMeta.TokenEndpoint, strings.NewReader(params.Encode())) 401 + req, err := http.NewRequestWithContext( 402 + ctx, 403 + "POST", 404 + authserverMeta.TokenEndpoint, 405 + strings.NewReader(params.Encode()), 406 + ) 373 407 if err != nil { 374 408 return nil, err 375 409 } ··· 403 437 DpopAuthserverNonce string 404 438 } 405 439 406 - func (c *OauthClient) RefreshTokenRequest(ctx context.Context, args RefreshTokenArgs, appUrl string) (any, error) { 440 + func (c *OauthClient) RefreshTokenRequest( 441 + ctx context.Context, 442 + args RefreshTokenArgs, 443 + appUrl string, 444 + ) (any, error) { 407 445 authserverMeta, err := c.FetchAuthServerMetadata(ctx, args.AuthserverUrl) 408 446 if err != nil { 409 447 return nil, err ··· 427 465 return nil, err 428 466 } 429 467 430 - dpopProof, err := c.AuthServerDpopJwt("POST", authserverMeta.TokenEndpoint, args.DpopAuthserverNonce, dpopPrivateJwk) 468 + dpopProof, err := c.AuthServerDpopJwt( 469 + "POST", 470 + authserverMeta.TokenEndpoint, 471 + args.DpopAuthserverNonce, 472 + dpopPrivateJwk, 473 + ) 431 474 if err != nil { 432 475 return nil, err 433 476 } 434 477 435 - req, err := http.NewRequestWithContext(ctx, "POST", authserverMeta.TokenEndpoint, strings.NewReader(params.Encode())) 478 + req, err := http.NewRequestWithContext( 479 + ctx, 480 + "POST", 481 + authserverMeta.TokenEndpoint, 482 + strings.NewReader(params.Encode()), 483 + ) 436 484 if err != nil { 437 485 return nil, err 438 486 }