I have a multi-tenanted app that I need to integrate with a Google API endpoint, lets say the Calendar API.
The application is organized much like Slack. You can create a namespace and invite users to it. The subdomain is used to separate namespaces, so there could be: foo.domain.com, bar.domain.com, and baz.domain.com.
A user, can belong to multiple namespaces, much like in slack where you can belong to different teams. So John can be a member of both foo and bar.
The problem is, when John decides he wants to give foo access to his calendar info, Google links the authorization to domain.com rather than foo.domain.com. When I attempt to give access his calendar to bar as well, there is no refresh token because technically John has already authorized the access... but I would like these to be treated independent. So that John is able to revoke access to foo.domain.com but continue to have bar.domain.com access his calendar data.
Is there a way to create independent authorizations for the same user to the same app? I can't share the refresh_token across subdomains as they may be physically separated, and I can't create a different app for each subdomain as they are dynamically generated.
The way authentication works is that its based upon the client you created in Google developer console.
If John grants your client access to his calendar data then that client will have access to his calendar data. Google has no way of knowing that its your foo or bar subdomains that have been granted access.
Multiple client option
You should probably created different client credentials for each of the different sub domains. Thats probably going to be the most logical way of doing it.
Single client option
Besides doing that you could store the information in your database someplace John has granted access to foo but not bar and store the refresh token for foo but not for bar and if he wants to delete it for foo then he can do that. You wont have to worry about keeping the refresh tokens updated as a user can technically have up to 50 refresh tokens associated with a single client.
Just watch it with revoke if the user does a revoke its going to revoke access to everything not just a single app.
Google's OAuth implementation only returns a refresh token in the response if the user explicitly clicked the "Authorize" button. This always happens the first time the user is prompted for authorization, but by default the consent screen is skipped when the same application asks for authorization again for the same scopes.
You can override this behavior, and force the user to see the consent screen again by adding the parameter prompt=consent in your authorization URL:
https://developers.google.com/identity/protocols/OpenIDConnect#re-consent
Doing so will ensure that a refresh token is returned each time. Keep in mind that a given user-application pair can only have 50 refresh tokens active at a time, after which older tokens will be invalidated:
https://developers.google.com/identity/protocols/OAuth2#expiration
Related
I have different web applications which are registered on IDM (vmware IDM https://github.com/vmware/idm/wiki/Integrating-Webapp-with-OAuth2#authentication-response)
As obvious, all applications are registered with there own client id and client secret. When a user tries to access webapp "A" (webappa.com), it redirects to my IDM login page and after authentication comes back with code that can be exchanged with access and refresh token.
Similar thing happens with webapp "B" etc. This works well. Now I am confused with following 2 use cases?
a. I want to use some API (webappa.com/api/v1/get_user_projects) from webapp "A" for some scripting purpose. So my question is how I can authenticate these APIs against the user? Can I get the tokens for the user from IDM provider by passing his credentials (using some APIs?). If answer to it is NO, then how usually it is handled?
b. Can webapp A and webaap B will have same access/ refresh token at a time against a user?
a.
When a user authenticates it is with certain permissions and for a certain period of time. OAuth is designed so that you can just forward tokens between microservices - but you cannot elevate the permissions or time for a user token. Depending on your use case you may want to consider a different token with different privileges for background tasks.
b.
It is possible but not advisable to follow the Google model via a cookie scoped to a web domain that hosts multiple apps, which is how Google do it (mail.google.com / drive.google.com). So there is a dependency on hosting and domains
The preferred option is for the user to authenticate at App A and then single sign on to App B. The different apps then get separate tokens with different permissions and can more easily evolve separately.
This also depends on how the app is implemented and your technology choices:
An 'old style' web app using a server side technology will expect to issue separate auth cookies per app
An SPA following an intelligent Back End for Front End design could support this model via SameSite cookies if it made sense for a set of related micro-UIs
In the latter case you would need to use a single OAuth client with multiple redirect URIs - eg for mail and drive - since the user could sign in to either of these first.
Apologies for the complicated answer - but it is a very architectural topic with the potential for hidden costs. From a stakeholder viewpoint it is very simple - make it work like Google. Hopefully this answer helps you in your conversations ...
I'm working at a company where we have a standard JWT token given to an end user. This user will get their JWT access token by going through the authorisation code oauth flow. By passing their access token into the Authorization header they can make calls into the microservice api's.
We now have a scenario where we need someone from the customer service centre assume the identity of an end user for the purpose of giving the service centre representative access to the users data for short period of time.
To solve this we have discussed having two access tokens flowing into the Authorization header in the microservice api's. The first would represent the customer service centre representative and the second would be the users access token but i am confused on how to best architect this solution.
Can anyone recommend a good solution staying as close to open id connect standards as possible. Microsoft seem to have an oauth flow named on behalf of which kind of matches what i want but seems more like it caters for a system on behalf of a user where I want a user on behalf of another user.
thanks
LONGER TERM
User Managed Access may provide solutions in this area:
End User sets a policy at the Authorization Server for their personal resources
A Company Administrator applies a policy at the Authorization Server for corporate resources (for multiple users)
A Requesting Party (app) presents claims as proof that they meet the policy
REAL WORLD
Almost no Authorization Servers support this capability, and even those that do may not do what you want. It is more than an OAuth pattern though, since a solution also ties into back end behaviour.
WHAT I WOULD DO
Build a solution around claims:
Service centre user logs in, to establish their own identity
After login, lookup claims, to see if the user has 'super' rights
If so, your UI presents an option to act on behalf of another user
Service center user types in email of who they are acting as
Update claims with the second identity
Authorization needs to take both identities into account
Auditing needs to log both identities
The above list hints at requirements, and of course not all of these can be solved with OAuth, but claims should give you the flexibility you need.
See my claims write up for how you could apply this pattern to collect claims from multiple places - not just access tokens. In your case, the ApiClaims object could include your database user ids for both users.
I am working on integrating Outlook's calendar REST API with my personal system.
Using the authorization code grant flow, I am able to get a user to login to an application that I have registered in https://apps.dev.microsoft.com. Once a user has logged in successfully, I receive a code on my redirect URL. Using the code, I fetch his bearer token (basic oAuth code flow).
Now, the confusion is with their documentation. They have 3 types of API, o365, outlook.office and graph. I am using their graph API for the calendar resource.
I'm using https://graph.microsoft.com/v1.0/me/calendarview to fetch events from the primary calendar, https://graph.microsoft.com/v1.0/me/events to create events in the primary calendar and https://graph.microsoft.com/beta/$batch for batch requests.
There are some scenarios that I want to cover here. When a user changes his/her outlook password, I need the user to re-login to the app so I can use a valid bearer token. From outlook documentation, it looks like the refresh token becomes invalid as soon as the user changes the password (search for refresh tokens become invalid); which means, at the worst case, I can use the bearer token for an hour (default) to authenticate the API's.
Is this normal of an oAuth flow? I always thought the bearer token would become invalid when a user changes the password.
Since I am working in an organization, I want my application to only be accessible by AD users in my organization.The application manifest has a field called availableToOtherTenants, which is defaulted to true. I changed the field to false so that only the users belonging to the organization AD can access it. But it looks like I am able to login to the application with my personal outlook account as well; in spite of this change.
What am I doing wrong here? Am I doing the right this by registering
an application in https://apps.dev.microsoft.com?
We are building a service that is expected to use MS Graph to send out emails to customers on a regular basis. Mailbox for sending out emails is setup like no-reply#contoso.com.
I have configured an app at https://apps.dev.microsoft.com. And since this service will be running on the server side to send out emails only, without user interaction, I opted to using the Application Permission named Mail.Send (admin only).
Such a setup requires admin consent. And my sys-admin is concerned that the app is requiring too much access that what it is intended to. He is right, as the requested permission will let the app/service send out emails as anyone in the organisation.
I know that I could use Delegate Permission option and get an auth code initially and let the service to continuously pickup a new access-token, based on refresh-token. I am not sure if this is idea.
First, congrats for having an on-the-ball Admin. What they're concerned about is frankly why Graph requires Admin Consent, the application permission scopes are fairly broad.
The only way to narrow the scope to a single user is to use Delegated permissions. If you request offline_access as part of your scopes, this will include the refresh_token that you'll need to remain logged in.
One important note on this model, you may need to periodically re-authenticate. Certain events such as changing passwords will nullify your tokens and require a fresh login to get a new set. You should be sure to include a notification mechanism that alters someone if the app is unable to refresh it's token.
Creating an angularjs single page application trying to use a RESTful API and I came across a problem that I can't seem to find an answer for. I was trying to prevent session hoping, one user logged in watching the requests figures out his account ID is 13. So he performs the same request but this time alters the request to get info for account ID 14.
So after the user logged in I was setting a session variable to his account ID and was going to strip the account ID out of the ajax requests. I then tried to access the Session from a class inheriting from ApiController. After looking around I realize that storing session information is not very RESTful.
So how would I go about ensuring that one account cannot access another account's information just because they watched the ajax requests and figured out how to manipulate the ajax request?
Is restful not meant to be used with users that need to authenticated and authorized? I was thinking of maybe hashing the IDs or something but I am not sure that is the right approach.
UPDATE:
I have token based authentication working now. But I am still in the dark as to how to prevent someone from fiddling with HTTP request and getting information that doesn't belong to him. For Example, I want to retrieve all the users for account with ID 14.
HTTP Get /users/14
I have a token so I know that the person trying to use the web API at some point authenticated themselves. I can lock it down to roles. But there is nothing stopping this authenticated person form fiddling/hacking with the request and doing the following
HTTP Get /users/58
Now the person has got all of account with ID 58's information. This is information does not belong to account 14 but now he can browse through other people's information.
I need someone of knowing that the request that comes from the browser and says it is for account with ID 14 that it really is account 14. I can put that information in the token but how do I check it in a handler or check it in the ApiController?
The problem you have described is not something unique to REST-based services. In fact, this is one of the top 10 OWASP vulnerabilities (Insecure Direct Object References). You will need to first identify the user and then authenticate the user. For identification, an ID is used, such as user ID. The identifier can be anything you want. After identification, you need to authenticate the user. This is done by authenticating the credential presented to the app, such as password. The identifier and the credential can be any thing, say the good old user name/password, or may be a token or may be an API key. It actually does not matter to the problem on hand. Once authenticated, you authorize the requests based on what the user can do in your app. The authz part is a must regardless of whether you use a token, certificate or what not. Hashing user ID or using some method to hide things is security by obscurity and is not a good practice.
Say, you are using a message handler to authenticate the credential submitted by a user. Once authentication is done you can store the account number associated with the authenticated user in the properties collection of HttpRequestMessage. This is done in the server side and no user can make the system store some random account number. Only the account number associated with the authenticated user is stored in the properties collection. With that, you can now authorize requests. Say, you can write an authorization filter that pulls this account number and compare it against the account number in the URI to determine if the request is allowed or not. By applying this filter against a GET action method, you can ensure only right folks can see right data.
For example, a user with user ID 'abc' and password 'pwd1' makes a GET request to /users/14. First step is, you will authenticate the user ID. If there is a user with ID 'abc' and password 'pwd1' in your store, you will consider the user authentic. As part of this authentication, you can pull the account number associated with the user 'abc'. Say it is 15. You will store 15 in request.properties. From your authorization filter, you can get the account number from URI, which is 14 and compare it against the one in the request, which is 15. Obviously the numbers do not match and you reject the request in the OnActionExecuting method of your filter with a 401.
What I described above is a simple approach. Better one (in terms of extensibility) will be to use claims but it will not be possible to explain all that here. You can get good amount of information related to claims-based identity from Dominick's blog.
Every request should be authenticated. If the credentials provided do not allow the user with account 13 to access data from account 14 then the request will be denied. The trick is to find a way to do authZ quickly.
You seem to be missing the information on how you want to implement authentication. As you correctly noted, using session to keep authentication information is not very restful. Here are the alternatives
Implement your own OAuth provider or use third party (for example
Azure ACS)
Implement STS provider (this is only for soap though)
Implement a custom token system, if you don't want to deal with
the above two. Basic system would take user id, salt it and encrypt with private key - but don't quote me on how secure that would be...
In all the cases, the authentication information is stored in the cookie, similar to session cookie. But it is still stateless.
The standard way on the web seems to be the oauth way, in fact the standard VS MVC template even comes with OAuth consumer implemented out of the box. So the question is, how do you link the oauth token to your internal user ID. That's really pretty simple, as you implement the "registration" step after the new user is authenticated - you keep user ID and oauth token in the database table, to link the two.
That link is quick to retrieve, and can be cached for speed. I have heard some people implement that type of credentials caching for some very big systems (google docs).