diff --git a/pkg/oauth/interactive.go b/pkg/oauth/interactive.go
index e745911a5..d9ee1234a 100644
--- a/pkg/oauth/interactive.go
+++ b/pkg/oauth/interactive.go
@@ -15,8 +15,120 @@
// Package oauth implements OAuth/OIDC support for device and token flows
package oauth
+import (
+ "bytes"
+ "fmt"
+ "text/template"
+)
+
+// GetInteractiveSuccessHTML is the page displayed upon success when using a web browser during an interactive Oauth token flow.
+// The page will close automatically if autoclose is true with the timeout specified.
+func GetInteractiveSuccessHTML(autoclose bool, timeout int) (string, error) {
+ const successTemplate = `
+
+
+ Sigstore Authentication
+
+
+
+
+
+
+
+
+
+
+ sigstore
+ authentication successful!
+
+ {{ if .Autoclose -}}
+
+
+
+ You may now close this page.
+
+
+ {{- else -}}
+
+ You may now close this page.
+
+ {{- end }}
+
+
+
+
+
+ {{ if .Autoclose -}}
+
+ {{- end }}
+
+
+`
+ // Parse the template
+ tmpl, err := template.New("success").Parse(successTemplate)
+ if err != nil {
+ return "", fmt.Errorf("error parsing success template: %w", err)
+ }
+ // Pass autoclose and timeout to the template
+ data := struct {
+ Autoclose bool
+ Timeout int
+ }{
+ autoclose,
+ timeout,
+ }
+ var htmlPage bytes.Buffer
+ if err := tmpl.Execute(&htmlPage, data); err != nil {
+ return "", fmt.Errorf("error executing template: %w", err)
+ }
+ return htmlPage.String(), nil
+}
+
const (
- // InteractiveSuccessHTML is the page displayed upon success when using a web browser during an interactive Oauth token flow.
+ // InteractiveSuccessHTML (deprecated) is the page displayed upon success when using a web browser during an interactive Oauth token flow.
InteractiveSuccessHTML = `
diff --git a/pkg/oauth/oidc/interactive.go b/pkg/oauth/oidc/interactive.go
index a3ef49da9..71e329f94 100644
--- a/pkg/oauth/oidc/interactive.go
+++ b/pkg/oauth/oidc/interactive.go
@@ -129,6 +129,8 @@ type interactiveIDTokenSource struct {
oidp *coreoidc.Provider
extraAuthCodeOpts []oauth2.AuthCodeOption
browser browserOpener
+ autoclose bool // autoclose specifies whether to close window after successful authentication
+ autocloseTimeout int // autocloseTimeout specifies the time to wait before closing the window
}
var errWontOpenBrowser = errors.New("not opening that browser")
@@ -147,8 +149,21 @@ func (idts *interactiveIDTokenSource) IDToken(ctx context.Context) (*IDToken, er
codeCh := make(chan string)
errCh := make(chan error)
+
+ // get html success page with configured autoclose and autocloseTimeout settings
+ htmlPage, err := oauth.GetInteractiveSuccessHTML(idts.autoclose, idts.autocloseTimeout)
+ if err != nil {
+ return nil, err
+ }
+
// starts listener using the redirect_uri, otherwise starts on ephemeral port
- redirectServer, redirectURL, err := startRedirectListener(stateToken, oauth.InteractiveSuccessHTML, cfg.RedirectURL, codeCh, errCh)
+ redirectServer, redirectURL, err := startRedirectListener(
+ stateToken,
+ htmlPage,
+ cfg.RedirectURL,
+ codeCh,
+ errCh,
+ )
if err != nil {
close(codeCh)
close(errCh)
@@ -200,8 +215,8 @@ func (idts *interactiveIDTokenSource) IDToken(ctx context.Context) (*IDToken, er
}
// InteractiveIDTokenSource returns an `IDTokenSource` which performs an interactive Oauth token flow in order to retrieve an `IDToken`.
-func InteractiveIDTokenSource(cfg oauth2.Config, oidp *coreoidc.Provider, extraAuthCodeOpts []oauth2.AuthCodeOption, allowBrowser bool) IDTokenSource {
- ts := &interactiveIDTokenSource{cfg: cfg, oidp: oidp, extraAuthCodeOpts: extraAuthCodeOpts, browser: failBrowser}
+func InteractiveIDTokenSource(cfg oauth2.Config, oidp *coreoidc.Provider, extraAuthCodeOpts []oauth2.AuthCodeOption, allowBrowser, autoclose bool, autocloseTimeout int) IDTokenSource {
+ ts := &interactiveIDTokenSource{cfg: cfg, oidp: oidp, extraAuthCodeOpts: extraAuthCodeOpts, browser: failBrowser, autoclose: autoclose, autocloseTimeout: autocloseTimeout}
if allowBrowser {
ts.browser = browser.OpenURL
}
diff --git a/pkg/oauth/oidc/interactive_e2e_test.go b/pkg/oauth/oidc/interactive_e2e_test.go
index 9f8b58533..4d52c642b 100644
--- a/pkg/oauth/oidc/interactive_e2e_test.go
+++ b/pkg/oauth/oidc/interactive_e2e_test.go
@@ -84,10 +84,15 @@ func (suite *InteractiveOIDCSuite) TestInteractiveIDTokenSource() {
Scopes: []string{coreoidc.ScopeOpenID, "email"},
}
+ autoclose := false
+ autocloseTimeout := 0
+
ts := &interactiveIDTokenSource{
- cfg: cfg,
- oidp: provider,
- browser: browserOpener,
+ cfg: cfg,
+ oidp: provider,
+ browser: browserOpener,
+ autoclose: autoclose,
+ autocloseTimeout: autocloseTimeout,
}
go func() {
diff --git a/pkg/oauthflow/flow.go b/pkg/oauthflow/flow.go
index 38df9700e..28abcac50 100644
--- a/pkg/oauthflow/flow.go
+++ b/pkg/oauthflow/flow.go
@@ -19,6 +19,7 @@ import (
"context"
"encoding/json"
"errors"
+ "log"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/go-jose/go-jose/v3"
@@ -46,6 +47,17 @@ type OIDCIDToken struct {
Subject string // Subject is the extracted subject from the raw token
}
+// init
+func init() {
+ // set the default HTML page for the DefaultIDTokenGetter
+ htmlPage, err := soauth.GetInteractiveSuccessHTML(false, 10)
+ if err != nil {
+ log.Print("failed to get interactive success html, defaulting to original static page")
+ } else {
+ DefaultIDTokenGetter.HTMLPage = htmlPage
+ }
+}
+
// ConnectorIDOpt requests the value of prov as a the connector_id (either on URL or in form body) on the initial request;
// this is used by Dex
func ConnectorIDOpt(prov string) oauth2.AuthCodeOption {