damienbod / angular-auth-oidc-client

npm package for OpenID Connect, OAuth Code Flow with PKCE, Refresh tokens, Implicit Flow
https://www.npmjs.com/package/angular-auth-oidc-client
MIT License
1.15k stars 433 forks source link

Error: The STS URL MUST be provided in the configuration! #1161

Closed Kayes-Islam closed 3 years ago

Kayes-Islam commented 3 years ago

Describe the bug I am setting the .well-known endpoint but not the STS. Everything works fine but the error is thrown in the console:

Error: The STS URL MUST be provided in the configuration!

Here's my configuration:

    oidcConfigService.withConfig({
      authWellknownEndpoint: 'http://localhost:8080/auth/realms/MyRealm/.well-known/openid-configuration',
      // stsServer: 'http://localhost:8080/auth/realms/MyRealm',
      redirectUrl: "http://localhost:4200",
      clientId: 'public-client-app',
      scope: 'openid roles',
      responseType: 'code',
      triggerAuthorizationResultEvent: true,
      postLogoutRedirectUri: "http://localhost:4200",
      startCheckSession: false,
      silentRenew: true,
      useRefreshToken: true
      postLoginRoute: '/home',
      forbiddenRoute: '/forbidden',
      unauthorizedRoute: '/unauthorized',
      logLevel: LogLevel.Debug,
      historyCleanupOff: true
    });

I'm raising this as a bug because just setting the .well-known should be enough.

To Reproduce Steps to reproduce the behavior:

  1. Configure with just authWellknownEndpoint, do not configure stsServer.
  2. Check the console log.

Expected behavior Error should not be thrown in console.

Screenshots image

Desktop (please complete the following information):

damienbod commented 3 years ago

Hi @Kayes-Islam

we designed this that the STS url is always required and the well known endpoints when it does not match the STS base route, or is something different => some IDP are deployed like this.

Greetings Damien

Kayes-Islam commented 3 years ago

Thank you @damienbod , I would like to request to change it so that .well-known is the preferred configuration rather than STS url. My reasoning for this request is that .well-known endpoint should contain all the required URLs. I also found stsServer a little confusing and needed to figure out from the examples that the URL is the base of the auth server URL, from which the token/well-known etc are formed.

Although unrelated, the docs explaining stsServer may not be correct. It says:

This is the redirect_url which was configured on the security token service (STS) server. https://github.com/damienbod/angular-auth-oidc-client/blob/main/docs/site/angular-auth-oidc-client/docs/documentation/configuration.md

marklagendijk commented 3 years ago

I also found the non-standard term stsServer to be confusing. Most libraries use the term issuer instead. Since the .well-known configuration also defines the issuer, it makes sense to allow just configuring authWellknownEndpoint.

damienbod commented 3 years ago

Normally you only configure the stsServer, never the well known endpoints. This is only for the case when it is implemented in a non standard way. Renaming the stsServerto issuer or identityProvider, authService or something else would make sense but I am not sure about renaming this now at this stage.

Thanks for your feedback.

oidcConfigService.withConfig({
      stsServer: 'http://localhost:8080/auth/realms/MyRealm',
      redirectUrl: "http://localhost:4200",
      clientId: 'public-client-app',
      scope: 'openid roles',
      responseType: 'code',
      triggerAuthorizationResultEvent: true,
      postLogoutRedirectUri: "http://localhost:4200",
      startCheckSession: false,
      silentRenew: true,
      useRefreshToken: true
      postLoginRoute: '/home',
      forbiddenRoute: '/forbidden',
      unauthorizedRoute: '/unauthorized',
      logLevel: LogLevel.Debug,
      historyCleanupOff: true
    });
Kayes-Islam commented 3 years ago

@damienbod Sorry to drag this out. But my understanding is that .well-known discovery endpoint is in fact the standard way: https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata As per the standard, all the URLs needed to invoke a PKCE flow are in-fact mandatory part of the metadata:

Furthermore many libraries also require you to just set the .well-known, and they obtain the rest from metadata. For example this flutter package:

final AuthorizationTokenResponse result = await appAuth.authorizeAndExchangeCode(
                    AuthorizationTokenRequest(
                      '<client_id>',
                      '<redirect_url>',
                      discoveryUrl: '<discovery_url>',
                      scopes: ['openid','profile', 'email', 'offline_access', 'api'],
                    ),
                  );

In Asp.net Core, all you need to configure is the .well-known:

services
    .AddAuthentication()
    .AddJwtBearer(x =>
    {
        x.MetadataAddress = "http://keycloak:8080/auth/realms/AuthDemoRealm/.well-known/openid-configuration";
        x.TokenValidationParameters = new TokenValidationParameters
        {
            ValidAudience = "auth-demo-web-api"                    
        };
    });

Therefore I really think well-known first configuration approach will make using the library easier and more standard compliant.

damienbod commented 3 years ago

In .NET Core we define it using JWT or Introspection without the well known. You can define this is you want.

services
  .AddAuthentication()
  .AddJwtBearer(options =>
  {
      options.Authority = "https://dev-damienbod.eu.auth0.com/";
      options.Audience = "https://auth0-api1";
  });
marklagendijk commented 3 years ago

@damienbod yes, of course all libraries also allow to set all the config manually. But loading it from the well-known endpoint is usually the preferred way.

As far as I have seen practically all libraries use the following approach:

  1. Option 1: allow setting the well-known endpoint. Option 2: allow setting the issuer, and get the data from the derived well-known endpoint when other config is not set.
  2. If configured (as described in 1.) get the config from the well-known endpoint. Options that are manually configured override the config loaded from the well-known endpoint.
damienbod commented 3 years ago

"yes, of course all libraries also allow to set all the config manually. But of course loading it from the well-known endpoint is usually the preferred way."

The Authority is the bit which needs to be configuration. The ".well-known/openid-configuration" is standard. So to find the APIs it's the authority + wellKnown.

Then only thing you need is the authority, sts server URL, auth service, issuer, Idp or whatever each system call this. Every system names this different.

Both ways work fine. I chose stsServer (probably not the best name) and use the standard discovery spec the get the well known endpoint per spec. Most API implementations I know use the Authority. The MetadataAddress is not used in most implementations I see.

So this is your "standard" way, but not the standard way I see in most implementations. I don't see one better than the other. If I was to change this, I have not improved the code and confuse others using the authority. The only reason the authWellknownEndpoint in this implementation is because some IDP or STS do not implement this in a standard way and you need to look for this API in a completely different location.

Changing this would require a lot of effort and not improve the quality. Renaming the stsServer would be an improvement, but this would be a breaking change and require migration then.

Greetings Damien

marklagendijk commented 3 years ago

I didn't mean to say your approach was non-standard. I believe this library does what I described here:

Option 2: allow setting the issuer, and get the data from the derived well-known endpoint when other config is not set.

My recommendation would be (which, of course, you are free to ignore if you don't like them ;) ):

damienbod commented 3 years ago

I think issuer is not the right name, this is just in the tokens. authority instead of stsServer seems better. Good?

marklagendijk commented 3 years ago

I believe that issuer is another name for issuing authority: the party that is giving you the tokens. As far as I know even in federated setups the initial contact point will still sign the id_token with itself as issuer. So I think that issuer is a correct name here.

Although authority is also a correct term, I personally wouldn't use it because it is less clear as issuer, because issuer is used more often.

If you choose to use authority anyway, you could add a clear description on it, which explains mentions the term issuer.

damienbod commented 3 years ago

@marklagendijk thanks for your feedback.

I decided to go for authority, asked around and also checked other server client implementations. issuer would also be good, I find this naming really difficult to get right.

https://github.com/damienbod/angular-auth-oidc-client/pull/1166

very grateful for your feedback.

Greetings Damien

Kayes-Islam commented 3 years ago

Just to incorporate more information to the issue, I found here in OAuth 2.0 Authorization Server Metadata Spec, Section 5. Compatibility Notes that if there's a path component to the auth server URL, such as for a realm or a tenant etc, the .well-known should be https://example.com/.well-known/openid-configuration/issuer1 going forward. The norm I see used by most servers is https://example.com/issuer1/.well-known/openid-configuration, which is apparently the older way and should be transitioned out. To me that's also another strong case of supporting .well-known first configuration as the primary option.

damienbod commented 3 years ago

I am closing this issue now. I have not solved it exactly as you commented, maybe your way is better, maybe not, there is always many ways to solve everything. I use the authority + "well known" because this is used in most of the IDPs I know and it is easier to implement this. The well known parameter can be set, if the this does not match on your IDP. I also used the authority because it is the authority which issues the tokens and the iss claim in the tokens is not always the same and the authority. The lib works in all scenarios now, maybe not a perfect API for you, but everyone has different opinions on this, all which are valid.

Thanks for your help

Greetings Damien