-
Notifications
You must be signed in to change notification settings - Fork 0
/
provider.go
98 lines (83 loc) · 2.76 KB
/
provider.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package corner
import (
"context"
"fmt"
"github.com/coreos/go-oidc/v3/oidc"
"golang.org/x/oauth2"
)
// OIDC specific provider URLs
const (
AppleProviderURL = "https://appleid.apple.com"
)
// Provide implements various steps of the OpenID Connect flow.
type Provide interface {
Verify(ctx context.Context) (bool, error)
Redeem(ctx context.Context, code string) (context.Context, error)
Refresh(ctx context.Context) (context.Context, error)
}
// Provider represents an OpenID Connect provider, with client credentials.
type Provider struct {
*oidc.Provider
*oidc.IDTokenVerifier
*oauth2.Config
internal Config
}
// Config represents the configuration for an OpenID Connect provider.
type Config struct {
// Force usage of Provider specific constructors
providerURL string
// Client credentials
ClientID string
ClientSecret string
// Skip various checks
SkipChecks bool
}
// NewAppleProvider returns a new Apple Provider.
func NewAppleProvider(ctx context.Context, config Config) (*Provider, error) {
config.providerURL = AppleProviderURL
return newProvider(ctx, config)
}
// NewProvider returns a new Provider, e.g. Apple or Google.
func newProvider(ctx context.Context, config Config) (*Provider, error) {
provider, err := oidc.NewProvider(ctx, config.providerURL)
if err != nil {
return nil, fmt.Errorf("failed to create provider %q: %v", config.providerURL, err)
}
return &Provider{
Provider: provider,
IDTokenVerifier: provider.Verifier(&oidc.Config{
ClientID: config.ClientID,
SkipExpiryCheck: config.SkipChecks,
SkipIssuerCheck: config.SkipChecks,
SkipClientIDCheck: config.SkipChecks,
InsecureSkipSignatureCheck: config.SkipChecks,
}),
Config: &oauth2.Config{
Endpoint: provider.Endpoint(),
ClientID: config.ClientID,
ClientSecret: config.ClientSecret,
},
internal: config,
}, nil
}
// Redeem exchanges the OAuth2 authentication token for an ID token
func (p *Provider) Redeem(ctx context.Context, headers AuthHeaders) (*oauth2.Token, error) {
if p.internal.SkipChecks {
return (&oauth2.Token{}).WithExtra(map[string]any{
AuthTokenHeaderInternal: headers.AuthToken,
}), nil
}
return p.Config.Exchange(ctx, headers.AuthCode)
}
// Refresh exchanges the OAuth2 refresh token for an ID token
func (p *Provider) Refresh(ctx context.Context, headers AuthHeaders) (*oauth2.Token, error) {
if p.internal.SkipChecks {
return (&oauth2.Token{}).WithExtra(map[string]any{
AuthTokenHeaderInternal: headers.AuthToken,
}), nil
}
return p.Config.TokenSource(ctx, &oauth2.Token{RefreshToken: headers.AuthRefresh}).Token()
}
func (p *Provider) Verify(ctx context.Context, headers AuthHeaders) (*oidc.IDToken, error) {
return p.IDTokenVerifier.Verify(ctx, headers.AuthToken)
}