Skip to content

Commit 1a07994

Browse files
committed
support oidc implicit flow
1 parent f07b9e0 commit 1a07994

21 files changed

+593
-71
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
"json-bigint": "^1.0.0",
100100
"just-debounce": "^1.1.0",
101101
"just-throttle": "^4.2.0",
102+
"jwt-decode": "^4.0.0",
102103
"lodash.groupby": "^4.6.0",
103104
"remark-stringify": "^10.0.3",
104105
"sanitize-html": "^2.12.1",

pnpm-lock.yaml

Lines changed: 9 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/config/development.yaml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ batchActionsDisabled: false
2020
hideWorkflowQueryErrors: false
2121
auth:
2222
enabled: false
23-
providers:
23+
providers: # only the first is used. second is provided for reference
2424
- label: Auth0 oidc # for internal use; in future may expose as button text
2525
type: oidc # for futureproofing; only oidc is supported today
2626
providerUrl: https://myorg.us.auth0.com/
@@ -36,6 +36,17 @@ auth:
3636
audience: myorg-dev
3737
organization: org_xxxxxxxxxxxx
3838
invitation:
39+
- label: oidc implicit flow
40+
type: oidc
41+
flow: implicit
42+
# TODO: support optional issuer validation
43+
authorizationUrl: https://accounts.google.com/o/oauth2/v2/auth # discovery isn't supported for implicit flow. the endpoint must be provided directly
44+
clientId: xxxxxxxxxxxxxxxxxxxx
45+
scopes:
46+
- openid
47+
- profile
48+
- email
49+
callbackUrl: http://localhost:8080
3950
tls:
4051
caFile:
4152
certFile:

server/docker/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ docker run \
1515
-e TEMPORAL_ADDRESS=127.0.0.1:7233 \
1616
-e TEMPORAL_UI_PORT=8080 \
1717
-e TEMPORAL_AUTH_ENABLED=true \
18+
-e TEMPORAL_AUTH_FLOW_TYPE=authorization-code \
1819
-e TEMPORAL_AUTH_PROVIDER_URL=https://accounts.google.com \
1920
-e TEMPORAL_AUTH_CLIENT_ID=xxxxx-xxxx.apps.googleusercontent.com \
2021
-e TEMPORAL_AUTH_CLIENT_SECRET=xxxxxxxxxxxxxxx \

server/docker/config-template.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@ auth:
4040
providers:
4141
- label: {{ default .Env.TEMPORAL_AUTH_LABEL "sso" }}
4242
type: {{ default .Env.TEMPORAL_AUTH_TYPE "oidc" }}
43+
flow: {{ default .Env.TEMPORAL_AUTH_FLOW_TYPE "authorization-code" }}
4344
providerUrl: {{ .Env.TEMPORAL_AUTH_PROVIDER_URL }}
4445
issuerUrl: {{ default .Env.TEMPORAL_AUTH_ISSUER_URL "" }}
46+
authorizationUrl:: {{ default .Env.TEMPORAL_AUTH_AUTHORIZATION_URL "" }}
4547
clientId: {{ .Env.TEMPORAL_AUTH_CLIENT_ID }}
4648
clientSecret: {{ .Env.TEMPORAL_AUTH_CLIENT_SECRET }}
4749
callbackUrl: {{ .Env.TEMPORAL_AUTH_CALLBACK_URL }}

server/server/api/handler.go

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,15 @@ import (
4545
)
4646

4747
type Auth struct {
48-
Enabled bool
49-
Options []string
48+
Enabled bool
49+
Flow string
50+
ProviderURL string
51+
IssuerURL string
52+
AuthorizationURL string
53+
ClientID string
54+
CallbackURL string
55+
Scopes []string
56+
Options []string
5057
}
5158

5259
type CodecResponse struct {
@@ -110,17 +117,25 @@ func GetSettings(cfgProvider *config.ConfigProviderWithRefresh) func(echo.Contex
110117
}
111118

112119
var options []string
120+
var authProviderCfg config.AuthProvider
113121
if len(cfg.Auth.Providers) != 0 {
114-
authProviderCfg := cfg.Auth.Providers[0].Options
115-
for k := range authProviderCfg {
122+
authProviderCfg = cfg.Auth.Providers[0]
123+
for k := range authProviderCfg.Options {
116124
options = append(options, k)
117125
}
118126
}
119127

120128
settings := &SettingsResponse{
121129
Auth: &Auth{
122-
Enabled: cfg.Auth.Enabled,
123-
Options: options,
130+
Enabled: cfg.Auth.Enabled,
131+
Flow: authProviderCfg.Flow,
132+
ProviderURL: authProviderCfg.ProviderURL,
133+
IssuerURL: authProviderCfg.IssuerURL,
134+
AuthorizationURL: authProviderCfg.AuthorizationURL,
135+
ClientID: authProviderCfg.ClientID,
136+
CallbackURL: authProviderCfg.CallbackURL,
137+
Scopes: authProviderCfg.Scopes,
138+
Options: options,
124139
},
125140
BannerText: cfg.BannerText,
126141
DefaultNamespace: cfg.DefaultNamespace,

server/server/config/auth.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,28 @@ func (c *AuthProvider) validate() error {
5252
return nil
5353
}
5454

55-
if c.ProviderURL == "" {
56-
return errors.New("auth provider url is not")
55+
switch flowType := c.Flow; flowType {
56+
case "authorization-code":
57+
if c.ProviderURL == "" {
58+
return errors.New("auth provider url is not set")
59+
}
60+
if c.AuthorizationURL != "" {
61+
return errors.New("auth endpoint url is not used in auth code flow")
62+
}
63+
case "implicit":
64+
// TODO: support oidc discovery in implicit flow
65+
if c.ProviderURL != "" {
66+
return errors.New("auth provider url is not used in implicit flow")
67+
}
68+
// TODO: support optional issuer validation
69+
if c.AuthorizationURL == "" {
70+
return errors.New("auth issuer url is not set")
71+
}
72+
if c.ClientSecret != "" {
73+
return errors.New("no secrets in implicit flow")
74+
}
75+
default:
76+
return errors.New("auth oidc flow is not valid")
5777
}
5878

5979
if c.ClientID == "" {

server/server/config/config.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,19 +93,23 @@ type (
9393
}
9494

9595
AuthProvider struct {
96-
// Label - optional label for the provider
96+
// Optional. Label for the provider
9797
Label string `yaml:"label"`
9898
// Type of the auth provider. Only OIDC is supported today
9999
Type string `yaml:"type"`
100-
// OIDC .well-known/openid-configuration URL, ex. https://accounts.google.com/
100+
// OIDC login flow type. The "authorization-code" and "implicit" flows are supported
101+
Flow string `yaml:"flow"`
102+
// OIDC .well-known/openid-configuration URL, e.g. https://accounts.google.com/. Discovery unsupported in implicit flow.
101103
ProviderURL string `yaml:"providerUrl"`
102-
// IssuerUrl - optional. Needed only when differs from the auth provider URL
103-
IssuerUrl string `yaml:"issuerUrl"`
104-
ClientID string `yaml:"clientId"`
105-
ClientSecret string `yaml:"clientSecret"`
104+
// Optional. Needed only when differs from the auth provider URL. In implicit flow, enables token issuer validation.
105+
IssuerURL string `yaml:"issuerUrl"`
106+
// Required for implicit flow. OIDC authorization endpoint URL, e.g. https://accounts.google.com/o/oauth2/v2/auth
107+
AuthorizationURL string `yaml:"authorizationUrl"`
108+
ClientID string `yaml:"clientId"`
109+
ClientSecret string `yaml:"clientSecret"`
106110
// Scopes for auth. Typically [openid, profile, email]
107111
Scopes []string `yaml:"scopes"`
108-
// CallbackURL - URL for the callback URL, ex. https://localhost:8080/sso/callback
112+
// URL for the callback, e.g. https://localhost:8080/sso/callback
109113
CallbackURL string `yaml:"callbackUrl"`
110114
// Options added as URL query params when redirecting to auth provider. Can be used to configure custom auth flows such as Auth0 invitation flow.
111115
Options map[string]interface{} `yaml:"options"`

server/server/route/auth.go

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -59,26 +59,37 @@ func SetAuthRoutes(e *echo.Echo, cfgProvider *config.ConfigProviderWithRefresh)
5959

6060
providerCfg := serverCfg.Auth.Providers[0] // only single provider is currently supported
6161

62-
if len(providerCfg.IssuerUrl) > 0 {
63-
ctx = oidc.InsecureIssuerURLContext(ctx, providerCfg.IssuerUrl)
64-
}
65-
provider, err := oidc.NewProvider(ctx, providerCfg.ProviderURL)
66-
if err != nil {
67-
log.Fatal(err)
68-
}
62+
api := e.Group("/auth")
63+
switch providerCfg.Flow {
64+
case "authorization-code":
65+
if len(providerCfg.IssuerURL) > 0 {
66+
ctx = oidc.InsecureIssuerURLContext(ctx, providerCfg.IssuerURL)
67+
}
6968

70-
oauthCfg := oauth2.Config{
71-
ClientID: providerCfg.ClientID,
72-
ClientSecret: providerCfg.ClientSecret,
73-
Endpoint: provider.Endpoint(),
74-
RedirectURL: providerCfg.CallbackURL,
75-
Scopes: providerCfg.Scopes,
76-
}
69+
if len(providerCfg.AuthorizationURL) > 0 {
70+
log.Fatal(`authorization url should not be set for auth code flow`)
71+
}
7772

78-
api := e.Group("/auth")
79-
api.GET("/sso", authenticate(&oauthCfg, providerCfg.Options))
80-
api.GET("/sso/callback", authenticateCb(ctx, &oauthCfg, provider))
81-
api.GET("/sso_callback", authenticateCb(ctx, &oauthCfg, provider)) // compatibility with UI v1
73+
provider, err := oidc.NewProvider(ctx, providerCfg.ProviderURL)
74+
if err != nil {
75+
log.Fatal(err)
76+
}
77+
78+
oauthCfg := oauth2.Config{
79+
ClientID: providerCfg.ClientID,
80+
ClientSecret: providerCfg.ClientSecret,
81+
Endpoint: provider.Endpoint(),
82+
RedirectURL: providerCfg.CallbackURL,
83+
Scopes: providerCfg.Scopes,
84+
}
85+
86+
api.GET("/sso", authenticate(&oauthCfg, providerCfg.Options))
87+
api.GET("/sso/callback", authenticateCb(ctx, &oauthCfg, provider))
88+
api.GET("/sso_callback", authenticateCb(ctx, &oauthCfg, provider)) // compatibility with UI v1
89+
case "implicit":
90+
// The implicit flow is principally designed for single-page applications.
91+
// Fully delegated to the client.
92+
}
8293
}
8394

8495
func authenticate(config *oauth2.Config, options map[string]interface{}) func(echo.Context) error {

src/lib/components/top-nav.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777
{#if showNamespaceSpecificNav}
7878
<DataEncoderStatus />
7979
{/if}
80-
{#if $authUser.accessToken}
80+
{#if $authUser.idToken || $authUser.accessToken}
8181
<MenuContainer>
8282
<MenuButton variant="ghost" hasIndicator controls="user-menu">
8383
<img

0 commit comments

Comments
 (0)