I'm trying to work with API resources in Identity Server 4 and think there must be something I'm not understanding.
I have a SPA client app which needs to authenticate a user via the IdP then make authorized requests to an API resource on behalf of that user. The API is not scoped so I have defined some API claims associated with the API resource in Identity Server, but haven't bothered defining any scopes or scope claims for this resource.
However, I'm now confused about how to go about requesting access to this API resource as part of the OIDC flow. Typically I'd use scopes in the authorize request but in this case I don't have a scope to use. So in my implementation of IProfileService, when I'm building the claims to return, context.RequestedResources.ApiResources is empty.
So what is the correct process for requesting a token that provides access to a scope-less API resource? I'm pretty sure I'm missing some fundamental bit of knowledge here and I'm going to come out of this humbled and looking foolish. But they say there are no stupid questions, right?
A scope is a logical name for (a part of) functionality of the resource. So a resource without scopes would mean that the resource has no functionality. That's why a resource should have at one least scope. When a client requests a scope, it actually requests a certain piece of functionality.
This is also documented, though it's not very obvious. The following line actually creates the resource api1 with scope api1.
new ApiResource("api1", "My API")
And that's the confusing part in the documentation, both resource and scope have the same name: api1.
When you scroll down to the client configuration the scope is used:
AllowedScopes = { "api1" }
But in the api configuration it's the resource name:
options.Audience = "api1";
In other words, resource api1 with scope api1.
How this works, the client requests a scope which is linked to a resource (audience). The audience is set in the token, along with the requested scopes (to allow finer grained authorization inside the resource, e.g. when multiple scopes are implemented). The resource validates if the audience matches, having policies to filter by requested scopes. When there are no scopes requested by the client, by specification all configured scopes for the client are requested.
So it's necessary that the resource has at least one scope. The code above shows how to do this for an InMemory configuration. For the database configuration, make sure you add a scope to the ApiScopes table that references the resource in the ApiResources table.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With