Sounds like you are following standard behaviour of validating JWTs in the API, rather than using OpenID Connect - so all good. OIDC is mostly a client concern which led to some confusion on my part, and hence my original answer. I thought I'd add a couple of follow on points below, since they may be useful to you in future when working with Azure AD.
DISTINCT ACCESS TOKENS PER API
APIs registered in Azure AD APIs follow the rationale behind the Resource Indicators draft spec. Each access token can only be used by a single API. Therefore each API requires a Client ID to be registered, that is written to access tokens issued for that API.
OAUTH STANDARDS AND MULTIPLE APIs
When there are multiple APIs, the most standard OAuth 2.0 architecture in a same company setup is for a set of related APIs to forward access tokens to each other. Each API then validates the access token, which is a fast operation. This is very much recommended, and is sometimes called a zero trust architecture. In a microservices architecture this also allows user context to be maintained securely.
For this to work, a set of related APIs should be able to all declare the same audience, such as api.mycompany.com
. Meanwhile each API will have different scopes, to ensure that if an API outside the remit of the original client is called, the request is immediately rejected. See scope best practices for a real world example.
AZURE AD AND MULTIPLE APIs
For multiple APIs to call each other with Azure AD access tokens, token exchange must be used. This involves each API acting as a client, in which case the client secret you have registered will be used. An example request where the API acts as a client is shown below, from a Node.js sample of mine. Note that the API acting as a client sends its original token as a User Assertion:
const formData = new URLSearchParams();
formData.append('grant_type', 'urn:ietf:params:oauth:grant-type:jwt-bearer');
formData.append('client_id', this._configuration.graphClient.clientId);
formData.append('client_secret', this._configuration.graphClient.clientSecret);
formData.append('assertion', accessToken);
formData.append('scope', this._configuration.graphClient.scope);
formData.append('requested_token_use', 'on_behalf_of');
const options = {
url: this._configuration.tokenEndpoint,
method: 'POST',
data: formData,
headers: {
'content-type': 'application/x-www-form-urlencoded',
'accept': 'application/json',
},
httpsAgent: this._httpProxy.agent,
};
const response = await axios.request(options as AxiosRequestConfig) as any;
return response.data.access_token!;