+9
cmd/client_test/html/index.html
+9
cmd/client_test/html/index.html
+7
cmd/client_test/html/login.html
+7
cmd/client_test/html/login.html
+276
-2
cmd/client_test/main.go
+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
+12
cmd/client_test/types.go
+8
-3
go.mod
+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
+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
+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
}