@@ -162,7 +162,7 @@ var supportedAlgorithms = map[string]bool{
162
162
// parsing.
163
163
//
164
164
// // Directly fetch the metadata document.
165
- // resp, err := http.Get("https://login.example.com/custom-metadata-path")
165
+ // resp, err := http.Get("https://login.example.com/custom-metadata-path")
166
166
// if err != nil {
167
167
// // ...
168
168
// }
@@ -236,7 +236,19 @@ func (p *ProviderConfig) NewProvider(ctx context.Context) *Provider {
236
236
//
237
237
// See: https://openid.net/specs/openid-connect-discovery-1_0.html
238
238
func NewProvider (ctx context.Context , issuer string ) (* Provider , error ) {
239
- wellKnown := strings .TrimSuffix (issuer , "/" ) + "/.well-known/openid-configuration"
239
+ return NewProviderWithBaseUrl (ctx , "" , issuer )
240
+ }
241
+
242
+ // NewProviderWithBaseUrl uses the OpenID Connect discovery mechanism to construct a Provider.
243
+ //
244
+ // An identity provider may report its issuer as a path rather than a full URL. This is not spec
245
+ // conformant, but for example the case with Hashicorp Vault (e.g. /v1/identity/oidc/provider/default)
246
+ //
247
+ // With this constructor, discovery can still be used with a combination of baseUrl and issuer.
248
+ //
249
+ // See: https://openid.net/specs/openid-connect-discovery-1_0.html
250
+ func NewProviderWithBaseUrl (ctx context.Context , baseUrl , issuer string ) (* Provider , error ) {
251
+ wellKnown := baseUrl + strings .TrimSuffix (issuer , "/" ) + "/.well-known/openid-configuration"
240
252
req , err := http .NewRequest ("GET" , wellKnown , nil )
241
253
if err != nil {
242
254
return nil , err
@@ -262,11 +274,11 @@ func NewProvider(ctx context.Context, issuer string) (*Provider, error) {
262
274
return nil , fmt .Errorf ("oidc: failed to decode provider discovery object: %v" , err )
263
275
}
264
276
265
- issuerURL , skipIssuerValidation := ctx .Value (issuerURLKey ).(string )
277
+ issuerUrl , skipIssuerValidation := ctx .Value (issuerURLKey ).(string )
266
278
if ! skipIssuerValidation {
267
- issuerURL = issuer
279
+ issuerUrl = issuer
268
280
}
269
- if p .Issuer != issuerURL && ! skipIssuerValidation {
281
+ if p .Issuer != issuerUrl && ! skipIssuerValidation {
270
282
return nil , fmt .Errorf ("oidc: issuer did not match the issuer returned by provider, expected %q got %q" , issuer , p .Issuer )
271
283
}
272
284
var algs []string
@@ -275,20 +287,28 @@ func NewProvider(ctx context.Context, issuer string) (*Provider, error) {
275
287
algs = append (algs , a )
276
288
}
277
289
}
290
+
291
+ withBaseUrl := func (val string ) string {
292
+ if val != "" && ! strings .HasPrefix (val , "http" ) {
293
+ val = baseUrl + val
294
+ }
295
+ return val
296
+ }
297
+
278
298
return & Provider {
279
- issuer : issuerURL ,
280
- authURL : p .AuthURL ,
281
- tokenURL : p .TokenURL ,
282
- deviceAuthURL : p .DeviceAuthURL ,
283
- userInfoURL : p .UserInfoURL ,
284
- jwksURL : p .JWKSURL ,
299
+ issuer : issuerUrl ,
300
+ authURL : withBaseUrl ( p .AuthURL ) ,
301
+ tokenURL : withBaseUrl ( p .TokenURL ) ,
302
+ deviceAuthURL : withBaseUrl ( p .DeviceAuthURL ) ,
303
+ userInfoURL : withBaseUrl ( p .UserInfoURL ) ,
304
+ jwksURL : withBaseUrl ( p .JWKSURL ) ,
285
305
algorithms : algs ,
286
306
rawClaims : body ,
287
307
client : getClient (ctx ),
288
308
}, nil
289
309
}
290
310
291
- // Claims unmarshals raw fields returned by the server during discovery.
311
+ // Claims unmarshalls raw fields returned by the server during discovery.
292
312
//
293
313
// var claims struct {
294
314
// ScopesSupported []string `json:"scopes_supported"`
0 commit comments