3

I'm sure the answer is obvious, but it's eluding me at the moment.

I get a 403 when my code tries to call /connect/userinfo and the message is "insufficient_scope".

https://github.com/IdentityServer/IdentityServer3/blob/master/source/Core/Validation/TokenValidator.cs#L153

Above is the line of code that checks for the scope claim in a JWT and wants to find the value to be "openid" to make the /connect/userinfo endpoint work.

In my JWT, if it has something like:

"scope": "openid"

... then the endpoint is fine. Instead if I have:

"scope": ["openid", "email", "profile"]

... then it fails.

Am I supposed to never have a list/array of scope claims? Maybe I'm missing a configuration setting somewhere?

Update with code

Sorry. Of course code will make the problem clearer.

Client Store

    public ClientStore()
    {
        _clients = new List<Client>
        {
            new Client
            {
                AlwaysSendClientClaims = true,
                RequireConsent = false,
                Enabled = true,
                ClientName = @"MVC Client",
                ClientId = @"mvc",
                PostLogoutRedirectUris = new List<string>
                {
                    "http://localhost:8080/index.html"
                },
                RedirectUris = new List<string>
                {
                    "http://localhost:8080/loginCallback.html"
                }
            }
        };
    }

Scope store

    public ScopeStore()
    {
        var scopes = new List<Scope>
        {
            StandardScopes.OpenId,
            StandardScopes.Profile,
            StandardScopes.Email,
            StandardScopes.Address,
            StandardScopes.AllClaims,
            StandardScopes.RolesAlwaysInclude
        };

        _scopes = scopes;
    }

Startup.cs

        var certFile = env.ApplicationBasePath + "/cert.pfx";

        app.Map("/core", core =>
        {
            var factory = new IdentityServerServiceFactory();

            var configuration = new Configuration();
            configuration.AddJsonFile("config.json");

            var userService = new EndUserService(configuration.Get("ConnectionString"));
            factory.UserService = new Registration<IUserService>(resolver => userService);

            var scopeStore = new ScopeStore();
            factory.ScopeStore = new Registration<IScopeStore>(resolver => scopeStore);

            var clientStore = new ClientStore();
            factory.ClientStore = new Registration<IClientStore>(resolver => clientStore); 

            var cert = new X509Certificate2(certFile, "test");

            var idsrvOptions = new IdentityServerOptions
            {
                CorsPolicy = CorsPolicy.AllowAll,
                Factory = factory,
                RequireSsl = false,
                SigningCertificate = cert,
                LoggingOptions = new LoggingOptions() {
                    EnableWebApiDiagnostics = true,
                    EnableHttpLogging = true
                }
            };

            core.UseIdentityServer(idsrvOptions);
        });

Login.html

var config = {
    client_id: "mvc",
    redirect_uri: "http://localhost:8080/loginCallback.html",
    response_type: "id_token token",
    scope: "openid email profile",
    authority: "http://localhost:44319/core",
    post_logout_redirect_uri: "http://localhost:8080/index.html"
};
var mgr = new OidcTokenManager(config);

UPDATE #2

Shoot, it's a Mono versus Windows thing. Works fine in Windows, broken in Mono. Known issue apparently: https://github.com/IdentityServer/IdentityServer3/issues/1373#issuecomment-104756822

jerbersoft
  • 4,344
  • 9
  • 42
  • 48
ryan1234
  • 7,237
  • 6
  • 25
  • 36

2 Answers2

3

Turns out there is a bug with how Microsoft's JWT library interprets JWT claims. Described here: https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/153

Waiting for that pull request to be accepted or for the problem to be fixed in some other manner.

ryan1234
  • 7,237
  • 6
  • 25
  • 36
0

It looks like you are requesting scopes that are not enabled in the client's configuration in your Identity Server Implementation.

You should have a class with client's and their ScopeRestrictions like this. You'll need to add the email and profile scopes to this list of scopes.

Scott Brady
  • 5,498
  • 24
  • 38
  • I previously had no explicit value for ScopeRestrictions and the comments say if it's empty, then all scopes can be requested. I am using a ScopeStore and not an InMemory Scope list. Maybe that's a problem? All the InMemory factory stuff seemed just for demos and testing, not production. Is that correct? – ryan1234 May 21 '15 at 21:00
  • You need to explicitly state your scopes. In the upcoming v2 they're enforcing this for clients. It won't be anything to do with an explicit scope store or InMemory scope list (these scopes are defined in the OpenID Connect specification). Check you have the required scopes enabled in both your scope store and for the client you are using – Scott Brady May 21 '15 at 21:31
  • And yes, the InMemory factory is only recommended for development – Scott Brady May 21 '15 at 21:33
  • Yeah I checked and double check and I have the scopes enabled for the server as a whole (/.well-known/openid-configuration shows it) _and_ I have ScopeRestrictions set to default, which reads, "If empty, the client can request all scopes". The odd behavior is that in my Javascript client, if I ask for just the "openid" scope, things are fine. If I ask for "openid email", then the /connect/userinfo endpoint returns a 403. – ryan1234 May 21 '15 at 22:24
  • Just to reinforce the above: https://tools.ietf.org/html/rfc6750#section-3.1 You are asking for or require a claim or scope that your access token does not have, hence the 403. This is meant to happen. I can't explain much more without looking at your code. – Scott Brady May 22 '15 at 07:03
  • Added my code. Hope that helps. Maybe a really obvious problem. Thanks for your patience! =) – ryan1234 May 22 '15 at 16:16