Is this the correct way of using REST API + OAuth on top of the normal web page? - symfony

First of all, for the lack of words, I used "normal web page" on the title. Please let me explain that:
Recently, I have seen many websites such as shopify.com making the most out of the modern browsers support for html5 push-state and Ajax. Instead of submitting forms, requesting new pages I see them doing all that via their REST APIs. It seems to me like a very neat way to do things because it's faster (less page reload), and also allow greatly allows us to re-use the API code.
In these scenarios, the users access the service via the websites as they would normally do, however their interaction with the resources are powered by the REST APIs.
As I dive more into the documents, it seems like these API requests should be stateless yet should always have a mechanism to authorize/authenticate each request so I looked into OAuth2 for that purpose (Since I will need OAuth2 anyhow, to grant accesses to 3rd parties). Now, since in this particular circumstance the user's browser will act as the client to request the resources via REST, I want to know what is the recommended flow to do it.
Right now I plan to implement it as followed: (I'm using Symfony 2 with FOSRestBundle and FOSAuthServerBundle)
User should login via the web form as normal (Since we need to authenticate/authorize both for the normal web page as well as for the API Requests)
When the user logged in, immediately check if an OAuth client is already created for this user? If not then create it with GRANT_TYPE_IMPLICIT. If the client is already there, just retrieve it.
Proceed to normal OAuth authorize for Rest requests?
Edit 1:
Further research makes me think that I should not send back the refresh token to the JS app as this would be too dangerous if the browser is compromised. Perhaps I could store the refresh token for the user somewhere in the server backend once he/she is logged in, then can reserve a special link for the JS app to request for new access token when old one expires? This seems a bit messy to me tho.

Related

Authorization Code Grant: is it safe to send the tokens to the client?

Let's say I have a SPA with a back-end on the same domain. If I had to connect to an external OAuth provider (let's say Google), the Authorization Code Flow (without PKCE) is the safer option. This means that:
The SPA requests a code to the Authorization Server
Then, it sends that code to the back-end
The back-end exchanges the code (and a secret) with the AS in order to get the tokens
The back-end sets a Session Cookie with the SPA to keep the user logged in
This flow is the most secure because the SPA never sees a single token. It doesn't use them. If I have to make a request to the API with the Access Token, the SPA will make a request to the back-end which in turn will use the Access Token to get the resources. And the back-end is also responsible for using the Refresh Token. So far so good.
Now, what if the back-end, upon successful exchange (once it gets the tokens), sends the tokens back to the browser? That way, the client can hit the API's endpoints on its own.
In theory, this should be avoided if I'm not mistaken. Giving the tokens back to the front-end kinda defeats the purpose of the Authorization Code Grant, you might as well use the Authorization Code w/ PKCE in order to get the tokens on the front-end directly, right? With the Code Grant, it's the back-end that gets authenticated, not the SPA.
But I'm thinking: that's what Firebase does, isn't it? As far as I know, Firebase uses the Authorization Code (without PKCE), redirects to the Firebase App's back-end (__auth/handler) and then it still gives the tokens to the front-end (id token, access token, refresh token).
Am I missing something? Or is it ok to give the tokens to the front-end at the end of the Authorization Code Grant?
PS. Obviously, in the Firebase case, the back-end will not actually use those tokens, it relies on the browser ones that are sent in each request I imagine. In the case I mentioned though, the back-end stores those tokens so in theory I'll have 2 sets of tokens: the ones that the back-end received with the code exchange, and the ones that get sent to the browser (initially they're the same, but they're different after the first refresh). Should the back-end discard the tokens completely and rely on the browser ones? I assume it should, because if Refresh Token Rotation is enabled, the back-end would have an invalidated Refresh Token after the first refresh by the browser. This situation is driving me nuts. My opinion is that the tokens should remain on the back-end, but I'm trying to figure out how can the Firebase approach be safe.
Interesting isn't it? There are trade offs involved, and different technologies make different choices on how to use tokens.
SHORT ANSWER
If is not inherently unsafe to use access tokens in the browser. It is generally recommended to keep the tokens short lived, confidential and to store them only in memory.
Whether to use tokens like this may also depend on the data sensitivity and the opinions of your stakeholders.
BIG PICTURE
What we'd really like is for these two technologies to work in an equivalent technical way. After all, both typically need to do the same job, of calling APIs to access data and then presenting screens to users.
Web UIs
Mobile UIs
It is totally standard to use access tokens in a Mobile UI, but some people have concerns about doing so in a Web UI.
WEB UIs
One option is to keep tokens out of the browser and use a 'web back end', as you describe. Many people prefer this from a security viewpoint, but it has these downsides compared to a pure SPA architecture:
You have to double hop all calls to APIs via the web back end, which is less efficient
The need for a web back end that runs code to issue auth cookies can result in suboptimal hosting, where you are unable to deploy web resources using a Content Delivery Network
There are other complexities due to the two forms of back end credential: cookies for web and tokens for mobile
PROOF OF POSSESSION TOKENS IN 2021?
Hopefully these are not far away for public clients - where DPoP tokens can be sent between Web UIs and APIs. This will mean access tokens stolen from a browser cannot be replayed and will further reduce the need for web back ends:
DPoP Proposed Standard
BROWSER THREATS
Of course there is more to browser security than cookies v tokens, and security is about covering risks. It is worth thinking about threats that concern you and how to mitigate them - this blog post has some notes on how I reasoned this out for an online code sample of mine a while back:
Browser Threat Model

Authentication & Authorization in AngularJS

I'm an ASP.NET MVC developer and I recently started to learn AngularJS as it seems like a more modern technology.
However, there's a few complications in my mind when it comes to authentication and authorization in AngularJS. In particular, AngularJS with ASP.NET Web API as the backend.
After authentication and getting the token from the api, I would imagine using Angularjs to store the token in the cookie. So any further requests will include the token. Say for some reason, the token expires, the next angularjs request to the api will fail with unauthorized. However, on the client side, angular thinks that it's authenticated (cookies) and will keep using that invalid token on all requests. I can think of a solution, which is to check for the "unauthorized" response on every request and redirect to login if that's the case. But I would probably be shot for such a practice.
In ASP.NET MVC, protecting a certain page/resource is as simple as adding [Authorize]. But in angular, it seems to be very complicated. How do I many protect many pages againsted the unauthenticated? Do I have to setup and interceptor for every route, etc?
Same goes for Authorization, what if the authenticated user attempts to access, say, the admin panel or parts of admin panel. How do I redirect to unauthorized page if they accessed by direct URL.
There can be many ways of solving your dilemma, but let me give you some tips that I generally use to authenticate and authorize.
Your app has to authenticate with the API (regardless of .NET or otherwise), which may happen by a login request that sets a cookie (during a server redirect), or perhaps a login endpoint the returns a token (like using oAuth). Either way, you have to store the authorization token so Angular can access it. I use cookies or localStorage myself. Then when a user is authenticated, I have a user service store that so I can use it anywhere in the app.
Once this happens, you can use a request http interceptors to attach the authorization header to your request. You can also use a response error interceptor to catch when the token no longer is accepted (usually a 401 status code, easy to check for), and force a login again. This should address issue #1 you raise.
Then for issue #2 and #3, if you are using uiRouter, you can listen for state change events (particularly $stateChangeStart). If I have an admin page, I'll name it admin.whatever and then have a change event that checks if the state has admin or not, and redirect users who are not admins. Likewise, I can do the same for all states to detect if there is no currently logged in user and force a login redirect.
Hope that gives you some ideas, it sounds like you're on the right track but need to hook into the Angular features.
This isn't really an answer but I'm in the same boat as you. I've built some basic Angular pages and small SPA app but now I'm trying to tie it all into an MVC app using .Net Identity. Surprisingly there isn't much out there about this topic. I did come across an good example but it was with .Net Core and MVC 6 which I'm not ready to jump into yet. It's worth watching and might give you some ideas.
http://stephenwalther.com/archive/2015/01/29/asp-net-5-and-angularjs-part-6-security
A couple days ago I came across this video and for the most part it seems to address the issue. It's the only thing that I've found so far with MVC 5, Angular and some .Net Authorization. Take a look and see if it gives you any ideas. I haven't had a chance to implement it yet but I'm hoping to get started doing that in the next couple of days. If you learn or find anything post it here.
https://www.youtube.com/watch?v=f67PFtrldGQ&nohtml5=False

Is it possible to use an external Identity Provider in a Web API with ASP.NET 5?

Reading this question, #Pinpoint's answer and the further discussion on comments, I'm well aware that natively we can't add an identity provider to our apps developed with ASP.NET 5. One possible replacement for the legacy OAuthAuthorizationServerMiddleware is then provided by the AspNet.Security.OpenIdConnect.Server as I've found in many places.
Now, there is one point that I'm still unsure about all this because I'm really not an expert in security, so my knowledge about OAuth is not very deep. My doubt is the following: is it possible to use an external identity provider when using OAuth to protect one RESTful API?
Notice that I'm not talking about adding social login to one website, I'm talking about using one external identity provider in one RESTful API.
My point is, this makes me a little confused yet, because I always thought this should be a concern of my app.
So my question here is: when using OAuth and ASP.NET 5, is it possible to use an external identity provider, other than implementing one? If it is possible, how this works in short? I mean, my app still needs to be able to manage the identities of users, in the sense that it needs to manage claims and so on.
In that case, if it is really possible, how the flow would be? The external identity provider should issue the tokens? But how my app would be able to verify those tokens and manage users identities?
EDIT: One of the reasons I feel unsure about that is that when we use the UseOAuthAuthentication extension method, we set up one callback path which is described as
The request path within the application's base path where the user-agent will be returned. The middleware will process this request when it arrives.
Now, if we are developing a site, then this really does make sense. The person goes there, click a button to login with a provider like Facebook. The user is redirected to Facebook's page and then after he logs in, he is redirected to some page of the site.
On the other hand, with a RESTful API this is meaningless. There is no notion of being redirected.
This makes it seems that the usage of external providers is only for sites and not for RESTful API's. This is the main point of my question.
My doubt is the following: is it possible to use an external identity provider when using OAuth to protect one RESTful API?
Yes, it's definitely possible. This is exactly what you do when you use Azure Active Directory to protect your API endpoints:
app.UseOAuthBearerAuthentication(options => {
options.AutomaticAuthenticate = true;
options.Authority = "https://login.windows.net/tushartest.onmicrosoft.com";
options.Audience = "https://TusharTest.onmicrosoft.com/TodoListService-ManualJwt";
});
The next legitimate question is: if you can use the tokens issued by AAD to protect your API, why couldn't you do the same thing with Facebook or Google tokens?
Unlike Facebook or Google, AAD issues completely standardized tokens named JWT tokens that the OAuth2 bearer middleware can "read" and "verify" to determine whether the token is still valid and was really issued for your API (i.e if the audience attached with the token corresponds to your API. You can control this value using the resource parameter when making your authorization request).
You can't do something similar with FB or Google tokens, since they are totally opaque. Actually, it's not really surprising since these tokens have only one objective: allowing you to query FB or Google APIs, not your own ones (these social providers don't allow to set the audience of the access token).
Since you can't read the token yourself, the only option is to ask FB or Google whether it is still valid to make sure your API doesn't accept invalid tokens. That's something you can (easily) do with Facebook as they offer a "token inspection endpoint" you can query for that: https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow (see the Inspecting access tokens chapter). This way, you can ensure the token is not expired and determine the user corresponding to the token.
Sadly, this approach has two downsides:
You have to make an extra HTTP call to the Facebook endpoint to validate the access token, which implies caching received tokens to avoid flooding Facebook with too many requests.
As the access token is not issued for your own API, you MUST absolutely ensure that the access token was issued to a client application you fully trust, or it will allow any third party developer to use his own FB/Google tokens with your API without having to request user's consent. This is - obviously - a major security concern.
You can find more information in the last part of this SO answer (it's for Katana and about Dropbox, but you should get the idea): OWIN/OAuth2 3rd party login: Authentication from Client App, Authorization from Web API
So my question here is: when using OAuth and ASP.NET 5, is it possible to use an external identity provider, other than implementing one? If it is possible, how this works in short? I mean, my app still needs to be able to manage the identities of users, in the sense that it needs to manage claims and so on.
In that case, if it is really possible, how the flow would be? The external identity provider should issue the tokens? But how my app would be able to verify those tokens and manage users identities?
To work around the limitations mentioned in the previous part, the best option is - as you've already figured out - to create your own authorization/authentication server. This way, your API doesn't (directly) accept FB or Google tokens but the tokens issued by your own server, that can possibly redirect your users to FB or Google for authentication.
This is exactly what this sample does: https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/tree/vNext/samples/Mvc
The user is invited by the client application (Mvc.Client) to authenticate with your authorization server (Mvc.Server) so he can get an access token to later query the API (also in Mvc.Server). For that, the user is redirected to your authorization server, which itself offers you to authenticate with Google or Twitter.
When this external authentication step is done, the user is redirected back to your authorization server (Mvc.Server), where he's asked to give his consent for the client app (Mvc.Client) to access his personal data.
When the consent is given, the user is redirected back to the client application with the access token you can use to query the API endpoint.

Constrain clients to ones coming from the own app/website for unauthenticated web API

These are the criteria:
My users are unauthenticated.
My app is a single page web app (written in JavaScript) that uses RESTful web API endpoints to fetch data from my own server.
Objective: I'd like to constrain the web API to only allow requests from my own app, without requiring users to authenticate. Are there existing techniques for this?
The issue is that since the web app's code and the requests made by it are transparent to the client it can't hold a secret for authenticating with the server.
I thought about creating single-use access tokens on the server side, then use those from the client side for the API calls. Now this would make it harder to do requests from the outside, but still you could make requests if you fetch this token from the original website first (even if you'd have to do it for every request).
If it matters I'd implement this with an ASP.NET MVC website and ASP.NET Web API endpoints.
Similar to this question but not entirely the same.
Thanks in advance.
I asked pretty much the same question a couple of years ago, and for unauthenticated users, some kind of token is pretty much going to be your only option. It doesn't make it impossible to get unauthorized access to your API, but does make it a little more painful.
I took a slightly different approach in my solution, using 2 cookies to protect some anonymous GET requests. One of them was the anonymous identification cookie, which was used as an encryption salt for another custom cookie given to the page that delivered the javascript. Only when the API request received both of these cookies and the decrypted result was satisfactory did I allow the WebAPI to respond. But like I mentioned, this only makes it more painful to gain access outside of the javascript app, not impossible.
Here is a reference for using tokens in WebAPI: http://codebetter.com/johnvpetersen/2012/04/02/making-your-asp-net-web-apis-secure/

Interacting with QuickBooks Online V3 API

I'm writing a web application (that is not to be published by Intuit on their App Center thing) to interact with QuickBooks Online (QBO) for syncing purposes, using VB.NET and ASP.NET. I'm having a hard time understanding how to do this exactly or where to start. What I understand this this:
User accesses your web application and the "Connect to QuickBooks" button (that Intuit requires for In-App authorization) is displayed.
Before the button is clicked you send a HTTP request to get OAuth request credentials using your consumer credentials.
Once the user clicks the button they get redirected to QuickBooks Online (QBO) where they can sign in and then authorize access to a certain company, giving you authorized request credentials.
QBO then redirects back to your site indicating you have authorized request credentials in which you send a HTTP request to get access credentials.
Once you have the access credentials you are basically free to interact with the QBO V3 API.
Using the access credentials you can then construct HTTP requests that send a particular HTTP method with XML/JSON in the body to perform a corresponding CRUD operation in QBO and QBO sends a response to indicate whether it was successful or not.
When your application is done interacting with QBO you simply make sure the access credentials are stored somewhere safe and let the user continue on with their life.
(Side Question: Is this correct or did I miss something or misunderstand something?)
My main question: Do you, as the app developer, even need to construct these HTTP requests or do you use their SDK or something completely different and I'm just not getting it?
I've tried to figure this out but it sounds like you're supposed to construct this all from scratch but then I look in their SDK and they have classes for all the different entity types but then their serializer doesn't serialize correctly and they talk about their DataService class and how you use that to send objects over and using some JavaScript files they host that I have only seen referenced but not explained by them, or anyone really, and information I do find seems to be outdated/deprecated and ya...
Maybe it's just that I'm new to web development and all this is way over my head right now, which very well could be.
(Off-topic-sorta: Is it me or is their site ridiculously broken? It just seems like a lot doesn't work correctly or things are just hard to navigate and find...)
Anyways, thanks for any help anyone can offer. If I need to give more details or ask a different question or something, just let me know. New to this and it's harder than I thought to ask things haha.
My main question: Do you, as the app developer, even need to construct
these HTTP requests or do you use their SDK or something completely
different and I'm just not getting it?
This is entirely up to you, the developer.
If you want to roll your own and construct your own HTTP requests, you certainly can. You almost certainly will still want to use a pre-packaged OAuth library, as OAuth is not trivial to implement.
However, you could also certainly use an existing code library/DevKit too, in which case the library/DevKit will construct the HTTP requests for you.
The DevKits should contain example code to show you how to actually do this stuff, so that might be your best place to start.
You are on right track.
First of all you need to register with IPP to get
ConsumerKey,ConsumerKey secret and Application ID.
https://developer.intuit.com/docs/0025_quickbooksapi/0010_getting_started/0020_connect/0010_from_within_your_app/implement_oauth_in_your_app
if user don't have access token then 'connect to quickbooks' button shows up otherwise you can make it hidden.
request code : https://github.com/IntuitDeveloperRelations/IPP_Sample_Code/blob/master/QuickbooksAPI/DotNet/WebForms%20application/QuickBooksApiDotNetWebFormsSampleApp/OauthGrant.aspx.cs
access code : https://github.com/IntuitDeveloperRelations/IPP_Sample_Code/blob/master/QuickbooksAPI/DotNet/WebForms%20application/QuickBooksApiDotNetWebFormsSampleApp/OauthHandler.aspx.cs
After getting accesstoken, accesskey secret and realmID (companyid) save that to your database.
make sure to encrypt.
so next time same user connect to quickbooks they don't need to go through all of the above steps.
OAuthRequestValidator oauthValidator = new OAuthRequestValidator(accessToken, accessTokenSecret, consumerKey, consumerSecret);
ServiceContext context = new ServiceContext (appToken, companyID, IntuitServicesType.QBO, oauthValidator);
https://developer.intuit.com/docs/0025_quickbooksapi/0055_devkits/0150_ipp_.net_devkit_3.0/0002_synchronous_calls/0001_data_service_apis

Resources