We have a number of services that can be called by users via HTTP based protocols (SOAP/REST/WebDAV). The services support various authentication mechanisms (e.g. Basic, and OIDC Bearer tokens). Sometimes a service has to call another service without a live user. For that, we configure technical users, and service A can call B with the credentials of a technical user.
For OAuth/OIDC authentication via Bearer tokens, we use the JWT bearer token flow to acquire access tokens for our technical users: Service A creates a JWT with the name of the technical user and signs it with its own private key. It then calls the OIDC token endpoint with that token and receives an access token for its technical user X. It can then use this token as a bearer token to call service B, which will accept the token for user X. (For more information on the JWT bearer flow, cf. RFC 7523 section 2.1 and RFC 7521 section 4).
This works fine with our Connect2id test server and also with Salesforce, but we haven't been able to get it working with Azure. Accessing Azure's token endpoint always results in the following error response:
AADSTS50027: JWT token is invalid or malformed
According the Microsoft's documentation, this error can have any number of reasons:
doesn't contain nonce claim, sub claim
subject identifier mismatch
duplicate claim in idToken claims
unexpected issuer
unexpected audience
not within its valid time range
token format is not proper
External ID token from issuer failed signature verification.
When trying to find out more about Azure and the JWT bearer flow, the only solid information I've been able to locate is this article:
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow
It describes the "On-Behalf-Of" (OBO) flow, which as far as I understand is an extension (by Microsoft?) to the JWT bearer flow, adding a second JWT to the mix along with a parameter called "requested_token_use" set to "on_behalf_of". I can only find "requested_token_use" in relation to the special OBO flow, and its only value seems to be "on_behalf_of".
OBO flow isn't what we want, since it seems to allow a service X to turn a token received by service Y into another token, using the Y token and a self-generated X token to call the token endpoint. Our use case only has a self-generated X token and the name of the user who the app is permitted to impersonate.
After a lengthy trial & error phase we've come to the impression that OBO may in fact be the only (non-standard) version of the JWT bearer flow that Azure knows about, and that it may not support the "normal" JWT bearer flow we're trying to use at all. Is this correct, and we have no option but to give up trying to solve this scenario with standard OIDC when Azure is involved, or does Azure in fact also support the flow we've implemented and we're just doing something wrong (e.g. wrong audience or issuer in our JWT, or a mis-configured app in Azure)?
PS: Our code is written in Java and we use the Nimbus library for our OAuth/OIDC communication.
Related
Let's say you are developing a client side JavaScript SPA app (Angular), a backend API for this app (ASP.NET Core in my case) and you use an identity provider that implements Open ID Connect protocol (I'm using IdentityServer4).
Apparently the recommended way for securing the app is to use the OIDC implicit flow between the JavaScript app and the identity provider and if successful the JavaScript app gets an id token and an access token.
Now according to this documentation the JavaScript app is supposed to pass the access token in the headers whenever it calls the API. And I'm not sure what purpose does the id token serve in this case (besides customizing the UI in your JavaScript app)?
But this is the confusing part: The documentation also says you should never use the access token for authentication. But that is the token that my API receives in the request headers, how can it authenticate the user then? If my API receives Post(newRecord), and the API needs to internally fix some audit information on newRecord (i.e newRecord.CreatedBy = CurrentUsername), how can it do that without authenticating the caller??
I think I'm missing a piece of the puzzle. Please any help is deeply appreciated.
Short answer/suggestion
Use Access Token to access API endpoints. From API endpoints, you must use token introspection endpoint to validate token validity (active state) as well as obtain subject who authenticated at authorization server. IdentityServer provide support for this. Documentation is available from here.
Explanation
ID token is intended to be used by receiving client. It will allow your client to authenticate the end user and provide user specific customizations. This is the whole purpose of OpenID Connect (OIDC). On the other hand OAuth 2.0 provide an authorization framework. It replaces user credentials with access tokens, thus improving API access security (compared to basic authentication and storing user credentials everywhere). Hence OIDC is built on top of OAuth 2.0, you get both ID Token and Access token with OIDC flow.
But as you have figured out (and mentioned before), ID token is intended for client. There are could be exceptional cases where ID token get passed between client and a server. This is mainly when both are controlled by same party. But the access token is the key to access API endpoints, correctly.
Access tokens can be an opaque string or JWT. When it's a JWT, API can read and understand the token (self-contained). When it's opaque, only way to validate token at API endpoint is to use token introspection endpoint. If API can validate token validity, then it could grant access (authorize) request. Furthermore, if user details (subject) are available (through JWT or as introspection response), then user specific checks can be executed. This further extends to token scope values. But at the end of the day, you are authorizing the API request and not authenticating the user at API endpoint. That's the highlight. Hope things are clear now.!
I'm struggling to understand when to use a session cookie, or just use the IdP issued token as a bearer token.
Is the primary advantage of using an IdP issued token that you get a standards based mechanism for tokens (including ensuring non-tampering, as the JWT is signed)?
As opposed to using a proprietary vendor mechanism of converting it to a claim identity, and then to a custom session cookie (as per owin middleware)?
Doesn't the custom cookie approach have an advantage that one can add non-ipd issued claims (eg: from a system db)?
What other key advantage does using an idp issued id_token have over a cookie based session approach?
Is it maybe that a bearer token approach would not need caching on the server, so that one can re-use it to call 3rd party services that have a different audience value? Whereas the token would be lost if we used a cookie? (I'm reaching, I know, as I don't yet understand how calling 3rd party services works).
The Id token is meant for your user-facing app as proof of who the user is.
It is then up to your app how you choose to authenticate the user on future requests.
While technically you could just store the Id token and use that, as you mentioned, it cannot be extended since it is digitally signed.
Which for most our projects is no good.
At least in regular Azure AD (not sure about B2C), you cannot use the Id token to get an access token for another API.
In there, you would have to get an authorization code in addition to the Id token at the time of sign in,
and exchange that for an access token (which you then cache server-side).
If you use the Id token as an authentication token for your app, keep in mind that Id tokens issued from the token endpoint (when exchanging an authorization code in normal Azure AD) are not signed (I guess since you receive them as a response to your request + over HTTPS).
Only the Id token you get in the redirect back to your app is signed in normal AAD.
I am not sure if this applies to B2C as well.
Why do we need first contact the Oath Auth endpoint to get an auth code, and then once we have received the auth code we need to contact the Oauth Auth endpoint again to get the access token so that we can call a webservice?
Why not just return the access token in the first step, after the user has signed in successfully?
Also, how does the webservice (API) then verify that the access token is legit?
Why do we need first contact the Oath Auth endpoint to get an auth code, and then once we have received the auth code we need to contact the Oauth Auth endpoint again to get the access token so that we can call a webservice?
So the web service (or Relying Party) never sees the user's credentials.
And because of how this flow works, the user also cannot see the application's credentials.
User also can't get the access token to use it themselves, though that actually would not matter that much.. Implicit Grant Flow actually does what you want, allowing you to get an access token directly from the authorization endpoint. But that is mainly for Single Page Apps, for which that is the easiest option.
Authorization Code Grant flow allows the app to use a stronger authentication via a client secret or certificate.
This is called an OAuth dance by the way :)
Why not just return the access token in the first step, after the user has signed in successfully?
See my mention above about Implicit Grant flow.
Also, how does the webservice (API) then verify that the access token is legit?
By checking the digital signature. Azure AD (and B2C) publish public keys for the key pairs they use for signing at a well known endpoint.
The authentication pieces in an app must check the JWT signature is valid by the defined public key.
Lets say I have a web API that a native application needs to make requests to. This API needs to authenticate who the user is that's making these requests via the native app. OpenID Connect seems to be the right choice since it is about authentication rather than authorization with OAuth.
The native app sends the users credentials to the IDP and gets back an access token (for authorization) and an id token (for authentication). From what I understand of OIDC, the access token would be sent to the API but the id token is only for the native client app. That doesn't make sense to me because it's the API that cares about who the user is, not the native app.
So why isn't the id token also passed to the protected resource (aka the API)? If you don't pass the id token to the API, what guarantees that the access token is secure and can be used to authenticate the user? Otherwise it would seem to lose the benefit of using OIDC over OAuth.
The OIDC Specification is designed in a way that ID tokens are always for Clients (Native app) and Access tokens are for resources (APIs). The ID tokens are always JWT tokens, but the Access tokens can be of different type.
The purpose of Access token is not to authenticate but to Authorize (Delegated Authorization). If, for some reason, the resource server wanted to know about the user, it can call the user-info endpoint.
The security/validity of token exchange can be validated in several ways:
Using encryption/signature with Public/Private key model where Authorization server encrypts / signs the access token with its private key and resource server decrypts / verifies with the public key.
Using token introspection endpoint to validate the claims, validity of the token etc..
Other attributes like AUD , AZP help in validating the issued access tokens.
Some OIDC providers use ID_Tokens to access API's - this is different to the model suggested by OIDC specification
This article has detailed explanation about these scenarios.
When I first heard of OAuth was in ASP.NET Web API applications and I've used it as means of authorizing users to access resources on a RESTful API. By the time I felt I was using it right, but right now I think I got the idea wrong and this is the subject of this question.
At the time, I used OAuth in the following way: on the API there was a token endpoint to issue tokens. I created a login page in a SPA and posted the username and password to the token endpoint with a grant type password and the token that came back I started sending with each request.
When the request had the Authorization: Bearer [token] header with a token issued with some username on the login page I understood the request was being done "with the user logged in" and so I could authorize access to resources.
Studying OAuth deeper my conclusion is that my usage of OAuth was completely mistaken.
My understanding now is that OAuth is just for authorizing applications and not users. In that case when we make a request with the Authorization: Bearer [token] header we are saying identifiying to the resource server that the client making the request has been authorized to access the resource, but we are not saying anything about the user?
In that case, with OAuth we just can say what resources client applications can access but we have no information to decide whether the user is allowed or not to the resource? Because of that my initial usage is truly wrong right?
OAuth 2.0 can be used for authorizing a client (an application) to call an API. This authorization is done via an authorization grant.
The grant is given by the resource owner in the case of authorization code, implicit and resource owner password grant through authentication of the user with the authorization server and clicking accept on a consent screen.
The first two grant flows are interactive and require an agent that understands HTTP (redirection) responses.
Most authorization servers also support the client credentials grant. In this case, there's no user involved and a pre-registered client (application) uses its own client-id and secret to authenticate with the authorization server.
Which grant flow to use depends on the type of client you use and who owns the resource the client needs to access. I describe the differences in my answer here.