Identity Server 4 - using identity resources and API resources - identityserver4

I am setting up Identity Server 4, and I am not getting the relationship between scopes, API Resources, and Identity Resources. My understanding was that an API Resource could hold the collection of scopes, and the Identity Resource could hold the possible claims.
I call /connect/token to get a JWT, and it seems to only use the scope if I have defined it as a client attribute. Also, it only seems to return claims that I have directly added to the client.
What is the purpose of Identity Resources, and API Resources?

Best definition for Identity Resources is on IDS4 docs:
An identity resource is a named group of claims that can be requested using the scope parameter.
API Resources are a solution to grouping the scopes, per IDS4 docs they give us these additional features too
support for the JWT aud claim. The value(s) of the audience claim will be the name of the API resource(s)
support for adding common user claims across all contained scopes
support for introspection by assigning a API secret to the resource
support for configuring the access token signing algorithm for the resource

Related

How do I include custom scopes for a given Application in Azure AD's OpenID Connect Metadata discovery endpoint?

I have a REST API hosted in Azure App Services that defines custom scopes for restricting access to specific operations in the API to certain groups of users. When accessing the Azure's OpenID Connect Metadata discovery endpoint however, I can't seen to find a way to see my custom scopes for the API (or any API consumer registered in Azure). How do I make it so that my custom scopes show up in the discovery endpoint metadata?
This is the endpoint I'm using:
https://login.microsoftonline.com/{my_tenant_id}/v2.0/.well-known/openid-configuration
Obviously, this version of the endpoint concerns the whole tenant, so it makes sense that it would not have visibility about specific API's scopes in there.
However, when using this variation, which specifies the ClientID, I'd expect the data on the payload to concern that specific application:
https://login.microsoftonline.com/{my_tenant_id}/v2.0/.well-known/openid-configuration?appid={application_client_id}
This turns out not to be the case: all scopes shown in this endpoint are also the standard ones that AAD always returns for everything else:
"scopes_supported": [
"openid",
"profile",
"email",
"offline_access"
],
I'd expect one or both of the following to happen:
The main endpoint to return the combination of all scopes defined for all applications
The app-parameterized endpoint to return the scopes for that particular application
Without my custom scopes being present, it is currently impossible to leave it to a client to pick the scopes when using OpenIDConnect connection type, since the application cannot know which scopes to request to AAD after the initial call, which was one of the main points regarding the metadata endpoint from what I understood.
I asked this question in the Microsoft.Identity.Web repository and got a reply back from a Microsoft Identity PM that states exposing custom scopes in the metadata endpoint is currently not supported by design.
More information here:
https://github.com/AzureAD/microsoft-identity-web/discussions/1689#discussioncomment-2519799
I'll stop using the discovery endpoint in my scenario since it becomes useless if the scopes in it don't match my API scopes.

What scope does "idp" belong to in IdentityServer4?

My MVC client's access token contains an "idp" claim that my simple server-to-server client's token doesn't. I don't explicitly request idp on either clients, so where is this claim coming from? I thought it was part of "openid", and since it is available by default to MVC client, you don't need to request it, but I couldn't find any documentation/specification that confirms it. By the way, I am unable to add the openid scope to my serer-to-server client, as I am getting "invalid scope" error when I do that. What I am trying to do here is to get the "idp" claim into the token for my server-to-server client as well, but not sure if that's possible. Can someone point me to the right direction?
When you do server to server communication using the client-credentials flow, there is no user involved and hence the openid scope has no purpose. As its core purpose is to ask for the subject claim (the user Id).
The idp claim is not part of any scope and is usually added by IdentityServer.
Why do you neeed the idp claim? Your API and client both trusts the shared IdentiyServer.
idp claim in Identityserver stands for external identity provider (such as Google). That's why it does not have any sense when you request a token from your local IdP with "service_credentials" flow. If you are interested in the info about the token's issuer, just use iss claim instead. If you are sure you need the idp (or any other custom) claim in each and every token, you can involve a custom ClaimsService as I explained in my previous answer.

Azure AD / MSAL.js - is it safe to include the tenantId?

Is it safe to include the clientId and tenantId in the msal.js implementation? I believe i read Joonas Westlin say that embedding the ClientId is fine (I can't find the post now).
There is a place for it in the library so it seems that it is ok:
this.msal = new UserAgentApplication(
{
auth: {
clientId: this.clientId,
authority: `https://login.microsoftonline.com/${this.tenantId}`,
redirectUri: Uri + "/login",
},
However one would think such identifying information is to be kept secret.
Short answer: Yes, it's safe to include clientId and tenantId.
Your concern is valid since with JavaScript based applications (like SPA's) any information that you're putting in is potentially exposed to users and can be misused. Although tenantId and clientId aren't such information, client secret or keys would be something sensitive and to be avoided.
tenantId is available publicly anyway as part of the OpenID Discovery document for tenant. You can access it using a URL of this format
https://login.microsoftonline.com/{tenantID or tenantDomain}/v2.0/.well-known/openid-configuration
clientId is an identifier for your app registration. To answer your concern about including it.. clientId alone doesn't establish application's identity, you need to have client secret along with it as well, to be able to use application's identity.
So from a security standpoint any public client application (like a JavaScript based SPA or even a desktop native app) should not make use of client secret, as these applications can not keep it safely and it can get compromised. Secrets can only be handled by confidential clients like server based web application or backend daemon process.
Here is Microsoft guidance for Implicit grant flow which is usually the flow used by JavaScript/SPA apps - Microsoft identity platform and Implicit grant flow
Here is a similar SO post about clientid and tenantId with good explanation - Are the Azure Client Id, Tenant, and Key Vault URI considered secrets?
I couldn't quickly find the post from Joonas Westlin that you mention in question, but Joonas's advice about clientId is correct as usual.

How to specify Resource URI when acquiring access token for Azure AD V2 endpoint?

I have used ADAL.js in a previous project which supported only work accounts and am able to successfully acquire idtokens and then accesstokens to an API (ResourceURI: "https://myresource.com"). Works fine.
Now, I am trying to use MSAL.js for another project because there I need to support both work accounts (aad auth) and personal "Microsoft Accounts" (MSA). I am running into problems now trying to do the same thing as in my ADAL project.
The concept of "Resource" has seemingly vanished from AAD V2. So how does one specify the Resource url when acquiring an access token to the target API? So that the resulting accesstoken contains the ResourceURI in the AUD claim (which will be enforced by the API I am calling).
If I force add the Resource querystring parameter, thusly:
msalapp.acquireTokenSilent([], null, null, "resource=https%3A%2F%2Fmyresource.com")
I get the following error:
AADSTS901002: The 'resource' request parameter is not supported.
Documentation says to use SCOPE instead. But using:
msalapp.acquireTokenSilent(['https://myresource.com'])
results in:
AADSTS70011: The provided value for the input parameter 'scope' is not valid. The scope https://myresource.com openid profile is not valid. The scope format is invalid. Scope must be in a valid URI form <https://example/scope> or a valid Guid <guid/scope>..
So: how do I specify the Resource URI when acquiring the access tokens when working with the v2 endpoint via MSAL.js? Sorry the (usually pretty good) MSDN articles are not useful at all in this case...
In Azure AD v2.0 you need to use scopes, not resources.
If you have a resource, and want to get a token for all the permissions, you can use :
https://myresource.com/.default.
You can also be more fine grain: more information is available from https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Adal-to-Msal#scopes-for-a-v10-application (this is in C#, but the translation is straightforward)

Do IdentityServer4 API Resources require a secret?

Does not having a secret defined for an IdentityServer4 API Resource introduce a security vulnerability?
I'm a little confused on the Introspection Endpoint, when it is used, and whether or not someone could use the Introspection endpoint to bypass Authorization and access an API without a defined secret (by a POST with just the API name as a parameter).
Is this possible? Or is the introspection endpoint only authorized through defined clients that use something like the Client Credential Grant?
The introspection endpoint will only validate a posted token, it shouldn't accept an API name in its request.
It can be used to validate reference tokens (or JWTs if the consumer does not have support for appropriate JWT or cryptographic libraries). The introspection endpoint requires authentication using a scope secret.
http://docs.identityserver.io/en/release/endpoints/introspection.html
This shouldn't be an endpoint you need to implement, it is included by identity server in the same way as the '.well-known/openid-configuration'.
A use case for this endpoint would be an API being passed a token and wanting to confirm its genuine and still valid (not expired or revoked), the response would include the claims associated with the token (users claims with the tokens scope taken into consideration)
For introspection security considerations see the RFC 7662 Section 4
An API Resource requires a Client Secret when you are using the Authorization Code Flow as its sending claims on the back channel.
If you are using Reference tokens you will also require a Client Secret, as the access token is never presented to the client, but instead the reference token is passed from the client to the api resource, and then onto the identity server in exchange for the access token.
It really depends on the client and the flow.

Resources