Skip to content

Commit bb1be84

Browse files
authored
feat: Add remoteoauth helpers (TokenAuthTransport and TokenAuthEditor) (#1875)
These helpers can be used to inject dynamic tokens into requests. `TokenAuthTransport` is a `http.RoundTripper`, with optional custom rewriting capability `TokenAuthEditor(oauth2.TokenSource)` returns a `func(context.Context, *http.Request) error` to be used as a `RequestEditorFn` in openapi clients.
1 parent 11aaab4 commit bb1be84

File tree

2 files changed

+82
-0
lines changed

2 files changed

+82
-0
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package remoteoauth
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/http"
7+
8+
"golang.org/x/oauth2"
9+
)
10+
11+
// TokenAuthEditor returns a custom RequestEditorFn to inject the OAuth2 token
12+
func TokenAuthEditor(tokenSource oauth2.TokenSource) func(context.Context, *http.Request) error {
13+
return func(_ context.Context, req *http.Request) error {
14+
token, err := tokenSource.Token()
15+
if err != nil {
16+
return fmt.Errorf("remoteoauth: failed to get token: %w", err)
17+
}
18+
if token == nil {
19+
return errNilToken
20+
}
21+
22+
// Inject the token as the Authorization header
23+
token.SetAuthHeader(req)
24+
return nil
25+
}
26+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package remoteoauth
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"net/http"
7+
8+
"golang.org/x/oauth2"
9+
)
10+
11+
// TokenAuthTransport is a custom http.RoundTripper to inject the OAuth2 token
12+
type TokenAuthTransport struct {
13+
TokenSource oauth2.TokenSource // required
14+
15+
BaseTransport http.RoundTripper
16+
Rewriter RewriterFunc
17+
}
18+
19+
var errNilToken = errors.New("remoteoauth: nil token")
20+
21+
// RewriterFunc is a function that can be used to rewrite the request before it is sent
22+
type RewriterFunc func(*http.Request, oauth2.Token)
23+
24+
// RoundTrip executes a single HTTP transaction and injects the token into the request header
25+
func (t *TokenAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) {
26+
reqCopy := req.Clone(req.Context())
27+
28+
token, err := t.TokenSource.Token()
29+
if err != nil {
30+
return nil, fmt.Errorf("remoteoauth: failed to get token: %w", err)
31+
}
32+
if token == nil {
33+
return nil, errNilToken
34+
}
35+
36+
if t.Rewriter != nil {
37+
t.Rewriter(reqCopy, *token)
38+
} else {
39+
// Inject the token as the Authorization header
40+
token.SetAuthHeader(reqCopy)
41+
}
42+
43+
transport := t.BaseTransport
44+
if transport == nil {
45+
transport = http.DefaultTransport
46+
}
47+
48+
return transport.RoundTrip(reqCopy)
49+
}
50+
51+
// NewAuthTransport creates a new TokenAuthTransport with the provided TokenSource
52+
func NewAuthTransport(ts oauth2.TokenSource) http.RoundTripper {
53+
return &TokenAuthTransport{
54+
TokenSource: ts,
55+
}
56+
}

0 commit comments

Comments
 (0)