While educating myself about OpenID Connect the following scenario raised some questions. Most documentation available online about OIDC/OAuth assumes that a Resource Server is only accessed from a Client within the same “Authorization Realm”, meaning that the Client and all Resource Servers are protected by the same OIDC Provider (OP).
In the given scenario, the Client is protected by OP A and requires User A to login at OP A before being able to use the Client. By doing this, the Client also receives an Access Token from OP A which enables it to access Resource Server A on behalf of the user. So far so good.
User A also has an account in the Authorization Realm B and the Client needs to access the Resource Server B which is protected by OP B.
This Resource Server B is an API which calls other API's within the same Authorization Realm B. All these APIs/Resource Servers do not know anything about OIDC Providers outside their own Authorization Realm B. Resource Server B could not only be accessed from the Client from Realm A, but also from N amount of Clients from various Authorization Realms. In my current understanding, all Resource Servers in Realm B would have to accept tokens from the various OP's.
Which would mean:
A lot of configuration in all the APIs
Every time a new realm is added or removed, the configuration has to be updated for all APIs
I understand that Client A could obtain two Access Tokens. One from OP A und one from OP B. Common authorization libraries do not support this out of the box and this would increase the complexity the Client has to handle (managing/refreshing multiple tokens/sending the right token to the right endpoint). Also, it is not clear to me how the OIDC flow would look like when working with two tokens from two OP's.
The Client would redirect the user to OP A for authentication (because the Client itself is protected by OP A).
After receiving the ID and Access Token the user is allowed to use the Client and the Client has the necessary token for API A.
The Client would also request an Access Token from OP B which means the user has to authenticate at OP B
The user would either have to provide username/password at OP B or, if we use identity federation, OP B would redirect to OP A where the user already has a session, resulting in an Access Token from OP B for API B
The Client would use token B for calls to API B and token A for calls to API A
Are there other solutions to accept requests from Clients protected by another OP using OAuth/OIDC? It is obvious that there must be some sort of trust setup between the two realms. But how can this be achieved without affecting all the Resource Servers in realm B?
The simplest option tends to involve federated authentication:
User in realm A uses a UI owned by realm B
The UI redirects to Realm B OIDC provider
The UI redirects further to Realm A's OIDC provider
User authenticates with Realm A credential
A Realm A token is posted to the Realm B OIDC provider
A Realm B token is returned to the UI
The UI sends the Realm B token to a Realm B API
This in itself has pretty expensive prerequisites including trust to be configured between Realm A and Realm B OIDC providers. Once complete the code in UIs and APIs is pretty simple and the responsibilities are in the right places.
Other options, such as allowing logins in Realm A then calling APIs in both Realm A and Realm B are often impossible to implement in a good way in practice.
A lot of people want to do this sort of thing though - and maybe emerging standards such as JWT Bearer Token Exchange will help in the coming couple of years.
Related
I'm trying to implement authentication/authorization in my solution. I have a bunch of backend services(including identity service) under API Gateway, "backend for frontend" service, and SPA (React + Redux). I have read about OAuth2.0/OpenIdConnect, and I can't understand, why I shouldn't use Resource owner password flow?
A client ( my backend for frontend server ) is absolutely trusted, I can simply send users login/password to the server, then it forwards them to Identity server, receives the access token && refresh token and stores refresh token in memory(session, Redis, etc), and send the access token to SPA, which stores it in local storage. If SPA will send a request with the expired access token, the server will request a new one using refresh token and forwards the request to API Gateway with the new access token.
I think in my case a flows with redirects can provide worth user experience, and are too complicated.
What have I misunderstood? What potholes I'll hit if I'll implement authentication/authorization as I described above?
OAuth 2.0 specification's introduction section gives one key information on the problem it tries to solve. I have highlighted a section below,
In the traditional client-server authentication model, the client
requests an access-restricted resource (protected resource) on the
server by authenticating with the server using the resource owner's
credentials. In order to provide third-party applications access to
restricted resources, the resource owner shares its credentials with
the third party
As a summary what OAuth wants to provide is an authorization layer which removes the requirement of exposing end user credentials to a third party. To achieve this it presents several flows (ex:- Authorization code flow, Implicit flow etc.) to obtain tokens which are good enough to access protected resources.
But not all clients may able to adopt those flows. And this is the reason OAuth spec introduce ROPF. This is highlighted from following extraction,
The resource owner password credentials grant type is suitable in
cases where the resource owner has a trust relationship with the
client, such as the device operating system or a highly privileged
application.The authorization server should take special care when
enabling this grant type and only allow it when other flows are not
viable.
According to your explanation, you have a trust relationship with client. And your flow seems to be work fine. But from my end I see following issues.
Trust
The trust is between end user and the client application. When you release and use this as a product, will your end users trust your client and share their credentials.? For example, if your identity server is Azure AD, will end users share Azure credentials with your client.?
Trust may be not an issue if you are using a single identity server and it will be the only one you will ever use. Which brings us the next problem,
Support for multiple identity servers
One advantage you get with OAuth 2 and OpenID Connect is the ability to use multiple identity servers. For example, you may move between Azure AD, Identityserver or other identity servers which of customer's choice (ex:- they already use on internally and they want your app to use it). Now if your application wants to consume such identity servers, end users will have to share credentials with your client. Sometimes, these identity servers may not even support ROPF flow. And yet again TRUST become an issue.!
A solution ?
Well I see one good flow you can use. You have one front end server and a back-end server. I believe your client is the combination of both. If that's the case you could try to adopt authorization code flow. It's true your front end is a SPA. But you have a backend you can utilise to obtain tokens. Only challenge is to connect front end SPA with back end for token response (pass access token to SPA and store other tokens in back-end). With that approach, you avoid above mentioned issues.
Im a bit confused about oauth2 and OIDC.
So supposedly with OIDC we now get the id_token which uniquely identifies the user in the same oauth2 flow.
But my understanding is - oauth 2 came out earlier than OIDC and OIDC support is not universal even at this point.
So how do current APIs that use oauth2 (without OIDC) work?
Let's say there is a mobile app that needs to use some API.
Is the idea that after mobile app get's oauth2 access token -> they always have to hit some endpoint like /me using that access token which will then provide user id information? and thus the api has to track which access tokens have been given to each particular user?
Sry this question comes out like request for some trivia info - but Im really new to oauth2 & OIDC and just trying to understand and make sure im not missing anything....
OAuth 2.0 NOT an Authentication protocol.
OAuth 2.0 is more of a delegation protocol where the Resource Owner delegates certain permissions to a OAuth Client.
OIDC is an Authentication protocol built on top of OAuth 2.0.
OAuth 2.0 should be used where a user (Resource Owner) is delegating permissions to an Application (OAuth Client) to perform some action.
OIDC should be used where an an Application (OAuth Client) needs to some "Level of Assurance" that the user (Resource Owner) is who he says he is.
The Authentication is done by a Third-Party (Authorization Server). The id_token allows the Client to access information about the user that the Authorization Server knows about (and hopefully has performed some verification).
As jwilleke answered it, OAuth 2.0 is for authorization. OpenID Connect (OIDC) is built on OAuth 2.0 adds Authentication layer.
Basically, OAuth 2.0 delegate the client application to access a protected endpoint on-behalf of the resource owner. In simple words, end user authorise the application access a resource/service. In this process, application does not receive any detail about the end user so it cannot authenticate/detect(In OIDC, application receive the id token, which is self-sufficient enough to authenticate the end-user) end user.
Q : Is the idea that after mobile app get's oauth2 access token -> they always have to hit some endpoint like /me using that access token which will then provide user id information? and thus the api has to track which access tokens have been given to each particular user?
From OAuth 2.0 perspective, there is no end user information sharing. But the token issuing identity provider understand the tokens it issued. Internally it can map end user details, permissions and anything it requires to process it. With that, when the API (resource server) receive the access token, it can validate the token. Note that resource server and authorization could be the same or different. And these are implementation specific details. Alternatively one could use token introspection as defined in rfc7662 to detect validity of issues access tokens.
Example scenario
You have mobile app A. And it have the ability to use a service B (protected by Access tokens) which is exposed by service provider G. Assume there is a user Alex who have already registered at SP G so have access to service B and uses app A. And SP G have OAuth 2.0 implemented so service B accepts access tokens issued by SP G.
User Alex use App A and there is a functionality in the App A which need to consume service B. App A require authorisation from Alex to consume service B on-behalf of him/her. In doing so, there will be a user login process and at the end SP G issue access token to App A. Does it convey identity of Alex ? No it does not. But App A can now consume service B using access token it received. Service B fully understand and can validate access tokens issues by SP G. IMO This is OAuth 2.0 in nutshell.
p.s - Substitute known services like Google calendar, Google identity and your android app so that it make more sense.
I am working on creating an OpenID Connect (OIDC) Provider based around django-oidc-provider. I have been reading up on the OpenID Connect Spec, and I cannot figure out how access tokens are unique for a certain application.
Consider the following example with a user, Bob:
Bob wants to login to application A, so he goes to its interface and is redirected to the OIDC Provider. After authentication he is redirected (implicit flow) back to Application A with an ID token and an access token. He then makes a request at "/image/1" to A's API with his access token. The API uses the access token to reach out to the OIDC Provider to assert the user's identity as Bob. The API then returns the data at "/image/1" for user Bob, assuming that info exists. Bob continues to send his access token to A's API for any subsequent requests.
Then, Bob decides he wants to access application B's API. He sends B's API the same access token that he used with A's API. B's API reaches out to the OIDC Provider with the token and asserts the user's identity as Bob. B's API then returns the requested info for Bob.
What prevents this from happening? I see at least two possible solutions to this:
When reaching out to Google's token validation endpoint the "aud" parameter is returned. Application B's API would have to check this parameter to decide that the token is not valid for it's own API?
An additional scope must be added when requesting the token that is specific to the resource provider say "app-A-api". Then when an API is validating a token, the API would ensure the token contains the needed scope.
Which of these methods, or others, are in line with the OIDC spec?
If one of the above should be used, am I correct in assuming I should add a new /tokeninfo endpoint that returns the scope or aud, rather than add that info to the info returned at the /userinfo endpoint?
Any input is appreciated. I think a lot of my confusion comes from not seeing the "scope" param being used to delegate access to a resource provider in any OIDC examples.
I think the thing you are missing is that the application A and its API are two separate applications. So the tokens are issued for the application A. If the app-A-api uses the access token just for the user authentication, it's better to use an ID token - it can be validated without accessing the OAuth2 server. In this scenario, the app-A-api manages its user permissions by itself.
If the app-A-api needs the token to get a list of scopes (permissions) of its client, then use the access token. But in this scenario, the app-A-api (and app-B-api) are just accepting the access token - they are not the target audience (aud attribute) of the token. The application A is the audience of the tokens.
The APIs just check whether the access token contains scopes relevant for them. They trust the token issuer and it's up to the users to decide whether they trust the application A to perform actions on their behalf.
As an example, if a JavaScript application C (app-C) uses just Google Drive and Google Plus for its actions, then app-C will ask its user for an access token with scopes belonging to Google Drive and Google Plus. It will be just one token and both Google APIs will accept it.
And about the tokeninfo endpoint, it has it's own RFC called OAuth 2.0 Token Introspection, so you can check it.
(Apologies in advance for possible misuse of the word authentication/authorization)
I am building up several web applications that talks to each other with an identity provider that looks like this.
A -----> idP
/ \
/ \
/ \
\/_ _\/
B C
Where application A will make requests to B and C to push and pull data, and it has to do so in the context of the user that's using application A. Given that I am using OAuth2 on the idP, my first thought is using the bearer token issued by the identity provider, and pass that around to each application as a way to "login" from application A to B/C.
Problem with that approach is that B/C doesn't know who that bearer token belongs to. In order to make this work, I would have to create an end point on the idP to get user information that B/C can use to figure out the user. While this could work, I wanted to see if there was something more standard out there I can use. That's when I found OpenID Connect.
From what I can see, OpenID Connect basically replaces the bearer token with a JWT, and signs it with a private key to prevent tampering. Given that, here's the flow I am thinking of:
User authenticates against web application A, application A receives ID token from idP, create a logged in session for the user and store the ID token as part of the session
Application A needs to retrieve data from application B in the context of user, so it sends the ID token to application B as part of the request
Application B gets the ID token from the header, gets the public key from the idP, and validates the signature.
If signature is validated, then the rest of the JWT is validated (expiry, issuer, issued time stamp, audience)
If all the checks are valid, then the data is returned from B to A
I have a couple of question about using OpenID Connect in this manner:
In OpenID Connect, the JWT's audience field can contain multiple client IDs, but from what I understand, the idP is suppose to only return the client requesting for the token. So how does the idP know what other client ID to put into the audience field?
How to best handle logout? Since each application maintains its own session, my thinking is that logout should invalidate the individual sessions on application A/B/C, then the session on idP to completely logout. Would that be best handled with an AJAX request to each application?
Although this isn't answering directly your questions, let me add comments to it as I am currently asking myself similar questions. This is also based on my humble understanding.
Regarding the audience (aud claim) of an ID Token, at the time of initial registration, your client registration could include what other applications (registered as OAuth clients too) your client would like to access. This could then be used to always include such an audience list when an ID Token is issued for your client. Check also the azp (authorized party) claim that should contain your client id. That's said, I haven't seen examples of tools managing this at registration time.
About your comment of the ID Token replacing the bearer token (i.e. Access Token), I have been looking at a standard way (e.g. specific Authorization header) to pass an ID Token when calling another application, but I didn't find any. I am not sure if a standard Authorization Bearer should be used or if there is another standard way of passing an ID Token.
Note also that, as far as I saw, ID Tokens have limitations to be used beyond being a short-live token, as:
they cannot be refreshed when they expire (even refreshing the linked Access Token isn't returning a refreshed ID Token)
they cannot be revoked (even if the linked Access Token could be), e.g. to manage a logout
They seem to more intended to be used to initiate a session (in a way similar to SAML assertions), like what you described, but you would rather copy ID Token claims and additional information retrieved from the UserInfo endpoint into your session information as your session may last longer than the duration of the ID Token.
That being said, if we want to use an ID token as some evidence of the user authentication, this wouldn't work after the token is expired, so I am not sure that trying to keep and use it during a whole session is a good idea.
If this is used as part of a short chain of calls or to create a new session with downstream applications (including initiating a JWT grant type OAuth flow with the ID token as an evidence of user identity), this may be what this is targeted at.
After a real brain bending session today I feel like I understand 3-legged OAuth authentication fairly well. What I'm still having trouble understanding is the use of the User ID. The examples I have seen so far all seem to just arbitrarily assign a user ID at the top of the sample script and go. That confuses me.
Most of the sample code I have seen seems to center around the concept of using a user ID and the OAuth server's consumer key for managing an OAuth "session" (in quotes because I'm not trying to conflate the term with a browser "session"). For example, the database sample code I've seen stores and retrieves the tokens and other information involved based on the user ID and consumer key field values.
I am now in that state of uncertainty where a few competing fragments of understanding are competing and conflicting:
1) If my understanding of the OAuth session details record or "OAuth store" lookups is correct, via the consumer key and user ID fields, then doesn't that mandate that I have a disparate user ID for each user using my application that connects with an OAuth server?
2) If #1 is correct, then how do I avoid having to create my own user accounts for different users, something I am trying to avoid? I am trying to write software that acts as a front end for an OAuth enabled service, so I don't need to have my own user records and the concomitant maintenance headaches. Instead I'll just let the OAuth server handle that end of the puzzle. However, it seems to follow that the downside of my approach would be that I'd have to reauthorize the user every session, since without my own persistent user account/ID I could not lookup a previously granted "good to revoked" access token, correct?
3) What bothers me is that I have read about some OAuth servers not permitting the passing of a dynamically specified callback URL during the requesting of the unauthorized token, making the passing of a consumer key and a user ID back to yourself impossible. Instead you specify the callback URL when you register as a developer/consumer and that's that. Fortunately the OAuth server I'm dealing with does allow that feature, but still, if I was dealing with one that wasn't, wouldn't that throw a giant monkey wrench into the whole idea of using the consumer key and user id pair to index the OAuth session details?
This is an answer to the question by Lode:
Is it correct that not only the provider needs to have user ids (that sounds logical) but also the client? So the client (using OAuth as a login system) needs to create a user (with an ID) before successfully authenticating them via the OAuth server. Making you have a lot of empty user accounts when authentication fails or access is not granted.
It's possible to use OAuth for authentication of users without having local accounts at the consumer application, but you've got to have some kind of session mechanism (cookies/get params) in order to have some internal session representation in which you would store the oauth_token.
For example, if someone has landed to your web application, and your application is a consumer of some OAuth provider, you will have to create a local session at your site for the end-user: for example with a cookie. Then you send the end-user to the OAuth provider for authorization of a token, so that your application can get protected resources from the provider. Currently you know nothing about the user and you don't care about his identity. You just want to use some protected information from the provider.
When the user comes back from the provider after successful authorization and brings back the oauth_token, you now have to store this token in the session that you previously created for the user. As long as you keep your session (and the token if it's needed for further requests for resources), you can consider that the end-user is logged in. In the moment that you delete his session or the token expires, you can consider him no more logged-in. This way you don't have to make your own users DB table or storage mechanism.
However, if you need to have some persistent information about the users in your application, that will be used between user sessions (logins), you have to maintain your own users in order to know with which user to associate the information.
As for the difference between openid and oauth - from the perspective of local accounts, there is no difference. It's all the same. The difference is only that with openid you receive immediately some basic user info (email, etc.) while with oauth you receive a token and you have to make one more request to get the basic user info (email, etc.)
There is no difference however in regard to local accounts, if you're going to use OpenID or OAuth.
I will try to tell my view on the issues that you raised and hope that will clear things a little bit...
First, the idea is that the OAuth server is protecting some API or DATA, which third party applications (consumers) want to access.
If you do not have user accounts or data at your API behind the OAuth server, then why would a consumer application want to use your service - what is it going to get from you? That being said, I can't imagine a scenario, where you have an OAuth server and you don't have user accounts behind it.
If you just want to use OAuth for login of users, without providing user data through API, then it's better to use OpenID, but again you will have to have user accounts at your side.
Your point is correct that you make lookups via Consumer Key and (Your) User ID, and that is because of the protocol design.
The general flow is:
OAuth server (Provider) issues unauthorized Request Token to consumer application
Consumer sends the end-user to authorize the Request Token at the OAuth server (Provider)
After end-user authorizes the token, an access token is issued and given to the consumer (I've skipped some details and steps here, as they are not important for what I want to say, e.g. the consumer receives valid access token at the end)
On the authorization step, it's your OAuth server that create and save as a pair - which local user (local for the provider) authorized which consumer (consumer key-user id pair).
After that, when the consumer application want to access end-users DATA or API from Provider, it just sends the access token, but no user details.
The OAuth server (Provider) then, can check by the token, which is the local USER ID that has authorized that token before that, in order to return user data or API functionallity for that user to the consumer.
I don't think that you can go without local users at your side, if you are a provider.
About the callback question, I think there's no difference if you have dynamic or static (on registration) callback URL in regard to how you handle OAuth sessions with consumer keys and user id. The OAuth specification itself, does not mandate to have a callback URL at all - it's an optional parameter to have, optional to send every time, or optional to register it only once in the beginning. The OAuth providers decide which option is best for them to use, and that's why there are different implementations.
When the provider has a static defined callback URL in the database, connected with a consumer, it is considered a more secure approach, because the end-user cannot be redirected to a 'false' callback URL.
For example, if an evil man steals the consumer key of a GreatApp, then he can make himself a consumer EvilApp that can impersonate the original GreatApp and send requests to the OAuth server as it was the original. However, if the OAuth server only allows static (predefined) callback URL, the requests of the EvilApp will always end at the GreatApp callback URL, and the EvilApp will not be able to get Access Token.