summaryrefslogtreecommitdiff
path: root/pkg/oidc
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-04-16 17:01:39 -0600
committermo khan <mo@mokhan.ca>2025-04-16 17:01:39 -0600
commit0b29a5a4ca71870ab138687e2fc71d6bce2754db (patch)
tree0c8897d6efd734b620eab22e8f86e7e9b4d202ea /pkg/oidc
parent9e83b4b2e95254ba51c66ed15f400d3bec5712f1 (diff)
refactor: verify the id token on every request
Diffstat (limited to 'pkg/oidc')
-rw-r--r--pkg/oidc/id_token.go60
-rw-r--r--pkg/oidc/oidc.go11
-rw-r--r--pkg/oidc/oidc_test.go33
-rw-r--r--pkg/oidc/tokens.go4
-rw-r--r--pkg/oidc/tokens_test.go20
5 files changed, 39 insertions, 89 deletions
diff --git a/pkg/oidc/id_token.go b/pkg/oidc/id_token.go
index 5fc1e63..ce4ae22 100644
--- a/pkg/oidc/id_token.go
+++ b/pkg/oidc/id_token.go
@@ -1,39 +1,33 @@
package oidc
-import (
- "bytes"
- "encoding/base64"
- "errors"
- "strings"
- "time"
+import "github.com/coreos/go-oidc/v3/oidc"
- "github.com/xlgmokha/x/pkg/serde"
-)
+type IDToken = oidc.IDToken
-type IDToken struct {
- Audience string `json:"aud"`
- Email string `json:"email"`
- EmailVerified bool `json:"email_verified"`
- ExpiredAt int64 `json:"exp"`
- IssuedAt int64 `json:"iat"`
- Issuer string `json:"iss"`
- Name string `json:"name"`
- Nickname string `json:"nickname"`
- Picture string `json:"picture"`
- Subject string `json:"sub"`
- UpdatedAt time.Time `json:"updated_at"`
-}
+// type IDToken struct {
+// Audience string `json:"aud"`
+// Email string `json:"email"`
+// EmailVerified bool `json:"email_verified"`
+// ExpiredAt int64 `json:"exp"`
+// IssuedAt int64 `json:"iat"`
+// Issuer string `json:"iss"`
+// Name string `json:"name"`
+// Nickname string `json:"nickname"`
+// Picture string `json:"picture"`
+// Subject string `json:"sub"`
+// UpdatedAt time.Time `json:"updated_at"`
+// }
-func NewIDToken(raw string) (*IDToken, error) {
- sections := strings.SplitN(raw, ".", 3)
- if len(sections) != 3 {
- return nil, errors.New("Invalid token")
- }
- b, err := base64.RawURLEncoding.DecodeString(sections[1])
- if err != nil {
- return nil, err
- }
+// func NewIDToken(raw string) (*IDToken, error) {
+// sections := strings.SplitN(raw, ".", 3)
+// if len(sections) != 3 {
+// return nil, errors.New("Invalid token")
+// }
+// b, err := base64.RawURLEncoding.DecodeString(sections[1])
+// if err != nil {
+// return nil, err
+// }
- token, err := serde.FromJSON[*IDToken](bytes.NewReader(b))
- return token, err
-}
+// token, err := serde.FromJSON[*IDToken](bytes.NewReader(b))
+// return token, err
+// }
diff --git a/pkg/oidc/oidc.go b/pkg/oidc/oidc.go
index 0526142..200db69 100644
--- a/pkg/oidc/oidc.go
+++ b/pkg/oidc/oidc.go
@@ -4,14 +4,18 @@ import (
"context"
"github.com/coreos/go-oidc/v3/oidc"
+ xcontext "github.com/xlgmokha/x/pkg/context"
"golang.org/x/oauth2"
)
type OpenID struct {
- Provider *oidc.Provider
- Config *oauth2.Config
+ Provider *oidc.Provider
+ Config *oauth2.Config
+ OIDCConfig *oidc.Config
}
+var IDTokenKey xcontext.Key[*IDToken] = xcontext.Key[*IDToken]("id_token")
+
func New(ctx context.Context, issuer string, clientID, clientSecret, callbackURL string) (*OpenID, error) {
provider, err := oidc.NewProvider(ctx, issuer)
if err != nil {
@@ -27,5 +31,8 @@ func New(ctx context.Context, issuer string, clientID, clientSecret, callbackURL
Endpoint: provider.Endpoint(),
Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
},
+ OIDCConfig: &oidc.Config{
+ ClientID: clientID,
+ },
}, nil
}
diff --git a/pkg/oidc/oidc_test.go b/pkg/oidc/oidc_test.go
index ef6a4f6..b7715cf 100644
--- a/pkg/oidc/oidc_test.go
+++ b/pkg/oidc/oidc_test.go
@@ -2,48 +2,21 @@ package oidc
import (
"context"
- "net/http"
- "net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "github.com/xlgmokha/x/pkg/serde"
+ "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/test"
)
func TestOpenID(t *testing.T) {
t.Run("GET /.well-known/openid-configuration", func(t *testing.T) {
- srv := httptest.NewServer(nil)
- srv.Config = &http.Server{
- Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- require.Equal(t, "/.well-known/openid-configuration", r.URL.Path)
- require.NoError(t, serde.ToJSON(w, &Metadata{
- AuthorizationEndpoint: srv.URL + "/authorize",
- ClaimsSupported: []string{"aud"},
- CodeChallengeMethodsSupported: []string{"plain"},
- DeviceAuthorizationEndpoint: srv.URL + "/device/authorize",
- IDTokenSigningAlgValuesSupported: []string{"RS256"},
- Issuer: srv.URL,
- JWKSURI: srv.URL + "/jwks",
- MFAChallengeEndpoint: srv.URL + "/mfa",
- RegistrationEndpoint: srv.URL + "/users/new",
- RequestURIParameterSupported: false,
- ResponseModesSupported: []string{"query"},
- ResponseTypeSupported: []string{"code"},
- RevocationEndpoint: srv.URL + "/revoke",
- ScopesSupported: []string{"oidc"},
- SubjectTypesSupported: []string{"public"},
- TokenEndpoint: srv.URL + "/token",
- TokenEndpointAuthMethodsSupported: []string{"client_secret_post"},
- UserInfoEndpoint: srv.URL + "/users/me",
- }))
- }),
- }
+ srv := test.OIDCServer()
defer srv.Close()
openID, err := New(context.Background(), srv.URL, "client_id", "client_secret", "https://example.com/oauth/callback")
require.NoError(t, err)
- assert.Equal(t, srv.URL+"/authorize", openID.Provider.Endpoint().AuthURL)
+ assert.Equal(t, srv.URL+"/oauth/authorize", openID.Provider.Endpoint().AuthURL)
})
}
diff --git a/pkg/oidc/tokens.go b/pkg/oidc/tokens.go
index a326ff2..7ff3c07 100644
--- a/pkg/oidc/tokens.go
+++ b/pkg/oidc/tokens.go
@@ -22,10 +22,6 @@ func (t *Tokens) ToBase64String() (string, error) {
return base64.URLEncoding.EncodeToString(data), nil
}
-func (t *Tokens) ParseIDToken() (*IDToken, error) {
- return NewIDToken(t.IDToken)
-}
-
func TokensFromBase64String(encoded string) (*Tokens, error) {
decoded, err := base64.URLEncoding.DecodeString(encoded)
if err != nil {
diff --git a/pkg/oidc/tokens_test.go b/pkg/oidc/tokens_test.go
index 3191f97..a7c5e13 100644
--- a/pkg/oidc/tokens_test.go
+++ b/pkg/oidc/tokens_test.go
@@ -4,7 +4,6 @@ import (
"bytes"
"encoding/json"
"testing"
- "time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -70,23 +69,4 @@ func TestTokens(t *testing.T) {
assert.Equal(t, "eyJ0eXAiOiJKV1QiLCJraWQiOiJ0ZDBTbWRKUTRxUGg1cU5Lek0yNjBDWHgyVWgtd2hHLU1Eam9PS1dmdDhFIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwOi8vZ2RrLnRlc3Q6MzAwMCIsInN1YiI6IjEiLCJhdWQiOiJlMzFlMWRhMGI4ZjZiNmUzNWNhNzBjNzkwYjEzYzA0MDZlNDRhY2E2YjJiZjY3ZjU1ZGU3MzU1YTk3OWEyMjRmIiwiZXhwIjoxNzQ0NzM3NDI3LCJpYXQiOjE3NDQ3MzczMDcsImF1dGhfdGltZSI6MTc0NDczNDY0OSwic3ViX2xlZ2FjeSI6IjI0NzRjZjBiMjIxMTY4OGE1NzI5N2FjZTBlMjYwYTE1OTQ0NzU0ZDE2YjFiZDQyYzlkNjc3OWM5MDAzNjc4MDciLCJuYW1lIjoiQWRtaW5pc3RyYXRvciIsIm5pY2tuYW1lIjoicm9vdCIsInByZWZlcnJlZF91c2VybmFtZSI6InJvb3QiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInByb2ZpbGUiOiJodHRwOi8vZ2RrLnRlc3Q6MzAwMC9yb290IiwicGljdHVyZSI6Imh0dHBzOi8vd3d3LmdyYXZhdGFyLmNvbS9hdmF0YXIvMjU4ZDhkYzkxNmRiOGNlYTJjYWZiNmMzY2QwY2IwMjQ2ZWZlMDYxNDIxZGJkODNlYzNhMzUwNDI4Y2FiZGE0Zj9zPTgwJmQ9aWRlbnRpY29uIiwiZ3JvdXBzX2RpcmVjdCI6WyJ0b29sYm94IiwiZ2l0bGFiLW9yZyIsImdudXdnZXQiLCJDb21taXQ0NTEiLCJqYXNoa2VuYXMiLCJmbGlnaHRqcyIsInR3aXR0ZXIiLCJnaXRsYWItZXhhbXBsZXMiLCJnaXRsYWItZXhhbXBsZXMvc2VjdXJpdHkiLCI0MTI3MDgiLCJnaXRsYWItZXhhbXBsZXMvZGVtby1ncm91cCIsImN1c3RvbS1yb2xlcy1yb290LWdyb3VwIiwiNDM0MDQ0LWdyb3VwLTEiLCI0MzQwNDQtZ3JvdXAtMiIsImdpdGxhYi1vcmcxIiwiZ2l0bGFiLW9yZy9zZWN1cmUiLCJnaXRsYWItb3JnL3NlY3VyZS9tYW5hZ2VycyIsImdpdGxhYi1vcmcvc2VjdXJpdHktcHJvZHVjdHMiLCJnaXRsYWItb3JnL3NlY3VyaXR5LXByb2R1Y3RzL2FuYWx5emVycyIsImN1c3RvbS1yb2xlcy1yb290LWdyb3VwL2FhIiwiY3VzdG9tLXJvbGVzLXJvb3QtZ3JvdXAvYWEvYWFhIiwibWFzc19pbnNlcnRfZ3JvdXBfXzBfMTAwIl19.SZu_l7tQ2Kkeogq0z8cRaDWPfv52JTo-RkiExbnud_lrfrXXneS77BIzaGKX_bzq4SM_oO_Q63AzK66B1r6Gp7ACo4DjOUEIWETg7ZBKcDzEZnresB7kmI_MJ5rfIJTmnH75GOfc_pl5l8T896TbaShN6zSpaXXIVEfhyUrflSWb4hhA7Hbwy2b6laXiaDv0qpcn1udPVYMTsll8I5ni_2yzuEPSVRgrcQoQ46OwVDZIi9tlfdT2qNVjH6FxJ3mkBcxtIVjf3_JYAawFEscg2uvQYwFWj9T6LleMknAh3QFJJMrS6mPqlXJGPUE5pTQgsBInfEikfm9PXxezA-IY6g", result.IDToken)
})
})
-
- t.Run("ParseIDToken", func(t *testing.T) {
- tokens := &Tokens{IDToken: "eyJ0eXAiOiJKV1QiLCJraWQiOiJ0ZDBTbWRKUTRxUGg1cU5Lek0yNjBDWHgyVWgtd2hHLU1Eam9PS1dmdDhFIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwOi8vZ2RrLnRlc3Q6MzAwMCIsInN1YiI6IjEiLCJhdWQiOiJlMzFlMWRhMGI4ZjZiNmUzNWNhNzBjNzkwYjEzYzA0MDZlNDRhY2E2YjJiZjY3ZjU1ZGU3MzU1YTk3OWEyMjRmIiwiZXhwIjoxNzQ0NzM3NDI3LCJpYXQiOjE3NDQ3MzczMDcsImF1dGhfdGltZSI6MTc0NDczNDY0OSwic3ViX2xlZ2FjeSI6IjI0NzRjZjBiMjIxMTY4OGE1NzI5N2FjZTBlMjYwYTE1OTQ0NzU0ZDE2YjFiZDQyYzlkNjc3OWM5MDAzNjc4MDciLCJuYW1lIjoiQWRtaW5pc3RyYXRvciIsIm5pY2tuYW1lIjoicm9vdCIsInByZWZlcnJlZF91c2VybmFtZSI6InJvb3QiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInByb2ZpbGUiOiJodHRwOi8vZ2RrLnRlc3Q6MzAwMC9yb290IiwicGljdHVyZSI6Imh0dHBzOi8vd3d3LmdyYXZhdGFyLmNvbS9hdmF0YXIvMjU4ZDhkYzkxNmRiOGNlYTJjYWZiNmMzY2QwY2IwMjQ2ZWZlMDYxNDIxZGJkODNlYzNhMzUwNDI4Y2FiZGE0Zj9zPTgwJmQ9aWRlbnRpY29uIiwiZ3JvdXBzX2RpcmVjdCI6WyJ0b29sYm94IiwiZ2l0bGFiLW9yZyIsImdudXdnZXQiLCJDb21taXQ0NTEiLCJqYXNoa2VuYXMiLCJmbGlnaHRqcyIsInR3aXR0ZXIiLCJnaXRsYWItZXhhbXBsZXMiLCJnaXRsYWItZXhhbXBsZXMvc2VjdXJpdHkiLCI0MTI3MDgiLCJnaXRsYWItZXhhbXBsZXMvZGVtby1ncm91cCIsImN1c3RvbS1yb2xlcy1yb290LWdyb3VwIiwiNDM0MDQ0LWdyb3VwLTEiLCI0MzQwNDQtZ3JvdXAtMiIsImdpdGxhYi1vcmcxIiwiZ2l0bGFiLW9yZy9zZWN1cmUiLCJnaXRsYWItb3JnL3NlY3VyZS9tYW5hZ2VycyIsImdpdGxhYi1vcmcvc2VjdXJpdHktcHJvZHVjdHMiLCJnaXRsYWItb3JnL3NlY3VyaXR5LXByb2R1Y3RzL2FuYWx5emVycyIsImN1c3RvbS1yb2xlcy1yb290LWdyb3VwL2FhIiwiY3VzdG9tLXJvbGVzLXJvb3QtZ3JvdXAvYWEvYWFhIiwibWFzc19pbnNlcnRfZ3JvdXBfXzBfMTAwIl19.SZu_l7tQ2Kkeogq0z8cRaDWPfv52JTo-RkiExbnud_lrfrXXneS77BIzaGKX_bzq4SM_oO_Q63AzK66B1r6Gp7ACo4DjOUEIWETg7ZBKcDzEZnresB7kmI_MJ5rfIJTmnH75GOfc_pl5l8T896TbaShN6zSpaXXIVEfhyUrflSWb4hhA7Hbwy2b6laXiaDv0qpcn1udPVYMTsll8I5ni_2yzuEPSVRgrcQoQ46OwVDZIi9tlfdT2qNVjH6FxJ3mkBcxtIVjf3_JYAawFEscg2uvQYwFWj9T6LleMknAh3QFJJMrS6mPqlXJGPUE5pTQgsBInfEikfm9PXxezA-IY6g"}
-
- idToken, err := tokens.ParseIDToken()
- require.NoError(t, err)
-
- assert.Equal(t, "e31e1da0b8f6b6e35ca70c790b13c0406e44aca6b2bf67f55de7355a979a224f", idToken.Audience)
- assert.Equal(t, "admin@example.com", idToken.Email)
- assert.Equal(t, true, idToken.EmailVerified)
- assert.Equal(t, int64(1744737427), idToken.ExpiredAt)
- assert.Equal(t, int64(1744737307), idToken.IssuedAt)
- assert.Equal(t, "http://gdk.test:3000", idToken.Issuer)
- assert.Equal(t, "Administrator", idToken.Name)
- assert.Equal(t, "root", idToken.Nickname)
- assert.Equal(t, "https://www.gravatar.com/avatar/258d8dc916db8cea2cafb6c3cd0cb0246efe061421dbd83ec3a350428cabda4f?s=80&d=identicon", idToken.Picture)
- assert.Equal(t, "1", idToken.Subject)
- assert.Equal(t, time.Time{}, idToken.UpdatedAt)
- })
}