this repo has no description
1package oauth
2
3import (
4 "context"
5 "fmt"
6 "io"
7 "net/http"
8 "net/url"
9 "time"
10)
11
12type OauthClient struct {
13 h *http.Client
14}
15
16type OauthClientArgs struct {
17 h *http.Client
18}
19
20func NewOauthClient(args OauthClientArgs) *OauthClient {
21 if args.h == nil {
22 args.h = &http.Client{
23 Timeout: 5 * time.Second,
24 }
25 }
26 return &OauthClient{
27 h: args.h,
28 }
29}
30
31func (o *OauthClient) ResolvePDSAuthServer(ctx context.Context, ustr string) (string, error) {
32 u, err := isSafeAndParsed(ustr)
33 if err != nil {
34 return "", err
35 }
36
37 u.Path = "/.well-known/oauth-protected-resource"
38
39 req, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil)
40 if err != nil {
41 return "", fmt.Errorf("error creating request for oauth protected resource: %w", err)
42 }
43
44 resp, err := o.h.Do(req)
45 if err != nil {
46 return "", fmt.Errorf("could not get response from server: %w", err)
47 }
48 defer resp.Body.Close()
49
50 if resp.StatusCode != http.StatusOK {
51 io.Copy(io.Discard, resp.Body)
52 return "", fmt.Errorf("received non-200 response from pds. code was %d", resp.StatusCode)
53 }
54
55 b, err := io.ReadAll(resp.Body)
56 if err != nil {
57 return "", fmt.Errorf("could not read body: %w", err)
58 }
59
60 var resource OauthProtectedResource
61 if err := resource.UnmarshalJSON(b); err != nil {
62 return "", fmt.Errorf("could not unmarshal json: %w", err)
63 }
64
65 if len(resource.AuthorizationServers) == 0 {
66 return "", fmt.Errorf("oauth protected resource contained no authorization servers")
67 }
68
69 return resource.AuthorizationServers[0], nil
70}
71
72func (o *OauthClient) FetchAuthServerMetadata(ctx context.Context, ustr string) (any, error) {
73 u, err := isSafeAndParsed(ustr)
74 if err != nil {
75 return nil, err
76 }
77
78 u.Path = "/.well-known/oauth-authorization-server"
79
80 req, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil)
81 if err != nil {
82 return nil, fmt.Errorf("error creating request to fetch auth metadata: %w", err)
83 }
84
85 resp, err := o.h.Do(req)
86 if err != nil {
87 return nil, fmt.Errorf("error getting response for auth metadata: %w", err)
88 }
89 defer resp.Body.Close()
90
91 if resp.StatusCode != http.StatusOK {
92 io.Copy(io.Discard, resp.Body)
93 return nil, fmt.Errorf("received non-200 response from pds. status code was %d", resp.StatusCode)
94 }
95
96 b, err := io.ReadAll(resp.Body)
97 if err != nil {
98 return nil, fmt.Errorf("could not read body for metadata response: %w", err)
99 }
100
101 var metadata OauthAuthorizationMetadata
102 if err := metadata.UnmarshalJSON(b); err != nil {
103 return nil, fmt.Errorf("could not unmarshal metadata: %w", err)
104 }
105
106 if err := metadata.Validate(u); err != nil {
107 return nil, fmt.Errorf("could not validate metadata: %w", err)
108 }
109
110 return metadata, nil
111}
112
113// func ClientAssertionJwt(clientId, authServerUrl string, clientSecretJwk jwk.Key) {
114// clientAssertion := jwt.NewBuilder().Issuer(clientId).Subject(clientId).Audience(authServerUrl).IssuedAt(time.Now().Add()
115// }
116
117func isSafeAndParsed(ustr string) (*url.URL, error) {
118 u, err := url.Parse(ustr)
119 if err != nil {
120 return nil, err
121 }
122
123 if u.Scheme != "https" {
124 return nil, fmt.Errorf("input url is not https")
125 }
126
127 return u, nil
128}