Skip to content

Commit e83f69d

Browse files
johnvan7sks
authored andcommitted
feat: add oauth-authorization-server discovery endpoint
Signed-off-by: Giovanni Vella <giovanni.vella98@gmail.com> Signed-off-by: sabith <sks@stackgen.com>
1 parent cfa86e0 commit e83f69d

5 files changed

Lines changed: 126 additions & 11 deletions

File tree

connector/oidc/oidc_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,17 @@ func setupServer(tok map[string]interface{}, idTokenDesired bool) (*httptest.Ser
862862
})
863863
})
864864

865+
mux.HandleFunc("/.well-known/oauth-authorization-server", func(w http.ResponseWriter, r *http.Request) {
866+
url := fmt.Sprintf("http://%s", r.Host)
867+
868+
json.NewEncoder(w).Encode(&map[string]string{
869+
"issuer": url,
870+
"token_endpoint": fmt.Sprintf("%s/token", url),
871+
"authorization_endpoint": fmt.Sprintf("%s/authorize", url),
872+
"jwks_uri": fmt.Sprintf("%s/keys", url),
873+
})
874+
})
875+
865876
return httptest.NewServer(mux), nil
866877
}
867878

server/api.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ func (d dexAPI) GetVersion(ctx context.Context, req *api.VersionReq) (*api.Versi
279279
}
280280

281281
func (d dexAPI) GetDiscovery(ctx context.Context, req *api.DiscoveryReq) (*api.DiscoveryResp, error) {
282-
discoveryDoc := d.server.constructDiscovery(ctx)
282+
discoveryDoc := d.server.constructDiscoveryOIDC(ctx)
283283
data, err := json.Marshal(discoveryDoc)
284284
if err != nil {
285285
return nil, fmt.Errorf("failed to marshal discovery data: %v", err)

server/handlers.go

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func (s *Server) handlePublicKeys(w http.ResponseWriter, r *http.Request) {
7171
w.Write(data)
7272
}
7373

74-
type discovery struct {
74+
type discoveryOIDC struct {
7575
Issuer string `json:"issuer"`
7676
Auth string `json:"authorization_endpoint"`
7777
Token string `json:"token_endpoint"`
@@ -89,8 +89,36 @@ type discovery struct {
8989
Claims []string `json:"claims_supported"`
9090
}
9191

92-
func (s *Server) discoveryHandler(ctx context.Context) (http.HandlerFunc, error) {
93-
d := s.constructDiscovery(ctx)
92+
type discoveryOAuth2 struct {
93+
Issuer string `json:"issuer"`
94+
Auth string `json:"authorization_endpoint"`
95+
Token string `json:"token_endpoint"`
96+
Keys string `json:"jwks_uri"`
97+
DeviceEndpoint string `json:"device_authorization_endpoint,omitempty"`
98+
Introspect string `json:"introspection_endpoint,omitempty"`
99+
GrantTypes []string `json:"grant_types_supported"`
100+
ResponseTypes []string `json:"response_types_supported"`
101+
CodeChallengeAlgs []string `json:"code_challenge_methods_supported,omitempty"`
102+
Scopes []string `json:"scopes_supported,omitempty"`
103+
AuthMethods []string `json:"token_endpoint_auth_methods_supported,omitempty"`
104+
}
105+
106+
type DiscoveryType int
107+
108+
const (
109+
DiscoveryOIDC DiscoveryType = iota
110+
DiscoveryOAuth2
111+
)
112+
113+
func (s *Server) discoveryHandler(ctx context.Context, t DiscoveryType) (http.HandlerFunc, error) {
114+
var d interface{}
115+
116+
switch t {
117+
case DiscoveryOAuth2:
118+
d = s.constructDiscoveryOAuth2()
119+
default:
120+
d = s.constructDiscoveryOIDC(ctx)
121+
}
94122

95123
data, err := json.MarshalIndent(d, "", " ")
96124
if err != nil {
@@ -104,8 +132,8 @@ func (s *Server) discoveryHandler(ctx context.Context) (http.HandlerFunc, error)
104132
}), nil
105133
}
106134

107-
func (s *Server) constructDiscovery(ctx context.Context) discovery {
108-
d := discovery{
135+
func (s *Server) constructDiscoveryOIDC(ctx context.Context) discoveryOIDC {
136+
d := discoveryOIDC{
109137
Issuer: s.issuerURL.String(),
110138
Auth: s.absURL("/auth"),
111139
Token: s.absURL("/token"),
@@ -141,6 +169,31 @@ func (s *Server) constructDiscovery(ctx context.Context) discovery {
141169
return d
142170
}
143171

172+
func (s *Server) constructDiscoveryOAuth2() discoveryOAuth2 {
173+
d := discoveryOAuth2{
174+
Issuer: s.issuerURL.String(),
175+
Auth: s.absURL("/auth"),
176+
Token: s.absURL("/token"),
177+
Keys: s.absURL("/keys"),
178+
DeviceEndpoint: s.absURL("/device/code"),
179+
Introspect: s.absURL("/token/introspect"),
180+
CodeChallengeAlgs: []string{codeChallengeMethodS256, codeChallengeMethodPlain},
181+
Scopes: []string{"offline_access"},
182+
AuthMethods: []string{"client_secret_basic", "client_secret_post"},
183+
}
184+
185+
// response_types_supported
186+
for responseType := range s.supportedResponseTypes {
187+
d.ResponseTypes = append(d.ResponseTypes, responseType)
188+
}
189+
sort.Strings(d.ResponseTypes)
190+
191+
// grant_types_supported
192+
d.GrantTypes = s.supportedGrantTypes
193+
194+
return d
195+
}
196+
144197
// handleAuthorization handles the OAuth2 auth endpoint.
145198
func (s *Server) handleAuthorization(w http.ResponseWriter, r *http.Request) {
146199
ctx := r.Context()

server/handlers_test.go

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func TestHandleHealth(t *testing.T) {
3939
}
4040
}
4141

42-
func TestHandleDiscovery(t *testing.T) {
42+
func TestHandleDiscoveryOIDC(t *testing.T) {
4343
httpServer, server := newTestServer(t, nil)
4444
defer httpServer.Close()
4545

@@ -49,10 +49,10 @@ func TestHandleDiscovery(t *testing.T) {
4949
t.Errorf("expected 200 got %d", rr.Code)
5050
}
5151

52-
var res discovery
52+
var res discoveryOIDC
5353
err := json.NewDecoder(rr.Result().Body).Decode(&res)
5454
require.NoError(t, err)
55-
require.Equal(t, discovery{
55+
require.Equal(t, discoveryOIDC{
5656
Issuer: httpServer.URL,
5757
Auth: fmt.Sprintf("%s/auth", httpServer.URL),
5858
Token: fmt.Sprintf("%s/token", httpServer.URL),
@@ -106,6 +106,51 @@ func TestHandleDiscovery(t *testing.T) {
106106
}, res)
107107
}
108108

109+
func TestHandleDiscoveryOAuth2(t *testing.T) {
110+
httpServer, server := newTestServer(t, nil)
111+
defer httpServer.Close()
112+
113+
rr := httptest.NewRecorder()
114+
server.ServeHTTP(rr, httptest.NewRequest("GET", "/.well-known/oauth-authorization-server", nil))
115+
116+
if rr.Code != http.StatusOK {
117+
t.Errorf("expected 200 got %d", rr.Code)
118+
}
119+
120+
var res discoveryOAuth2
121+
err := json.NewDecoder(rr.Result().Body).Decode(&res)
122+
require.NoError(t, err)
123+
124+
require.Equal(t, discoveryOAuth2{
125+
Issuer: httpServer.URL,
126+
Auth: fmt.Sprintf("%s/auth", httpServer.URL),
127+
Token: fmt.Sprintf("%s/token", httpServer.URL),
128+
Keys: fmt.Sprintf("%s/keys", httpServer.URL),
129+
DeviceEndpoint: fmt.Sprintf("%s/device/code", httpServer.URL),
130+
Introspect: fmt.Sprintf("%s/token/introspect", httpServer.URL),
131+
GrantTypes: []string{
132+
"authorization_code",
133+
"refresh_token",
134+
"urn:ietf:params:oauth:grant-type:device_code",
135+
"urn:ietf:params:oauth:grant-type:token-exchange",
136+
},
137+
ResponseTypes: []string{
138+
"code",
139+
},
140+
CodeChallengeAlgs: []string{
141+
"S256",
142+
"plain",
143+
},
144+
Scopes: []string{
145+
"offline_access",
146+
},
147+
AuthMethods: []string{
148+
"client_secret_basic",
149+
"client_secret_post",
150+
},
151+
}, res)
152+
}
153+
109154
func TestHandleHealthFailure(t *testing.T) {
110155
httpServer, server := newTestServer(t, func(c *Config) {
111156
c.HealthChecker = gosundheit.New()

server/server.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -447,11 +447,17 @@ func newServer(ctx context.Context, c Config) (*Server, error) {
447447
}
448448
r.NotFoundHandler = http.NotFoundHandler()
449449

450-
discoveryHandler, err := s.discoveryHandler(ctx)
450+
oidcHandler, err := s.discoveryHandler(ctx, DiscoveryOIDC)
451451
if err != nil {
452452
return nil, err
453453
}
454-
handleWithCORS("/.well-known/openid-configuration", discoveryHandler)
454+
handleWithCORS("/.well-known/openid-configuration", oidcHandler)
455+
456+
oauthHandler, err := s.discoveryHandler(ctx, DiscoveryOAuth2)
457+
if err != nil {
458+
return nil, err
459+
}
460+
handleWithCORS("/.well-known/oauth-authorization-server", oauthHandler)
455461
// Handle the root path for the better user experience.
456462
handleWithCORS("/", func(w http.ResponseWriter, r *http.Request) {
457463
_, err := fmt.Fprintf(w, `<!DOCTYPE html>

0 commit comments

Comments
 (0)