Problem
I need OAuth2 Tokens for the user accessing the browser from multiple OAuth serves in order to have access tokens for accessing multiple resources.
The OAuth authentication process triggers when the user clicks a single button. Let's call it Login.
Well not exactly what we are doing picture getting the user simultaneously authenticating using Google and Azure AD, so tokens for each can be obtained. (Having to manage individual credentials for each is an accepted pain point.)
The problem though is how to code up the JavaScript to trigger and manage authenticating with each where they both use callbacks and browser redirects. And they both must simply reload the users existing page storing the JWT of both in hidden form fields. (Using Session Storage is acceptable and happens anyway yet it must be retained between redirects.)
Restrictions
Changing the basic requirements is not possible
Adding new pages or radically changing the web application layout and pages is not possible
Using vanilla JavaScript web app that is not SPA. Each page can be semi-SPA yet ultimately passes JWT back to server for use and gets another page for additional user interaction with the resource data fetched by server.
No normal sever side coding possible. A special purpose engine is doing workflow orchestration and has limited low level coding capabilities.
Possible Solutions
Using hidden iframes may be possible if carefully managed and invisible to user
Synchronise authentication where one OAuth process completes before the other starts
Attempted
Using chained Promises, yet things get lost during the redirects, race conditions happen, and confusion breaks out.
To use change state events of hidden form fields to orchestrate synchronises authentication, i.e. when one completes setting form field to obtained token that other starts
Seeking
Some suggestions on how to solve the problem. Please indicate if your idea is something you've done or seen and know works, or something you think might work; I am grateful for both:-)
Hints at things that will not work and should be avoided.
I solved the problem by using the browser session state to orchestrate first authenticating with one provider and then after that finished doing the other.
The basic issue was to ensure that each time it reloaded the page after a redirect containing the authentication code the correct authentication provider would pick up the code and complete the operation fetching the token. The session state was used to store an indicator as each completed.
As they both used callbacks it was necessary to chain callbacks which was done by using promises.
Related
I have to create a SPA with Angular 8.
In the SPA I will have a component with a form that can only be seen if the user has permissions.
For this I had planned to use a route guard, the problem is that the guard runs in the client's browser, which does not guarantee that the component of the form is not seen by a malicious user (for example, editing the js).
There will be security in the RestAPI backend when receiving the form data (permission check and so on), but I need to make sure that the form cannot be seen by anyone who does not have permissions.
Is there a way to efficiently block the visualization of an angular component?
There is no denying that you client side code can not be accessed by malicious code alteration.
You can not do anything about it, as SPA code relies on front end so if you know the variables and can alter the functions from lets say console or otherwise, there is nothing you can do.
As far the access control goes or blocking UI elements goes, you can have strong back-end which will not authorized unauthorized access. This way only UI can be seen but the data required to function that UI will not be visible (due to back-end access control).
You can think it in logical way,
If the sensitive data is not visible then no problem if UI element is visible.
If some action button is visible to malicious user, as to perform this action you need back-end, this won't work as the malicious use wont have access to end endpoint.
Bottom line is your band-end should be very strong to handle authorized requests and separate itself from unauthorized requests.
I'm currently playing around with a KnockoutJS SPA template in ASP.NET Core 2.1, and I managed to implement an authorization flow exactly as this one which was made in Angular:
https://fullstackmark.com/post/13/jwt-authentication-with-aspnet-core-2-web-api-angular-5-net-core-identity-and-facebook-login
As you can see in their User front-end service, basically the only check for whether the user is logged in on the client side is the check if the "auth_token" key exists in the client's local storage:
https://github.com/mmacneil/AngularASPNETCore2WebApiAuth/blob/master/src/src/app/shared/services/user.service.ts
this.loggedIn = !!localStorage.getItem('auth_token');
// ?? not sure if this the best way to broadcast the status but seems to resolve issue on page refresh where auth status is lost in
// header component resulting in authed user nav links disappearing despite the fact user is still logged in
Simply put, anyone can open up the browser local storage and insert a random string with the "auth_token" key and they'll be able to see everything admin-related in the UI (even though they will fail on API requests).
Can someone suggest a better flow for this? Or is the only option to send a "log in request" to the API, whenever an admin page is "opened"?
P.S. I am relatively new to the authentication schemes front, should JWT perhaps not be used for client-side content validation?
Considering JWT best practices, all your validations should be done in your back-end, since any validation coded in your web app could be read by any of your clients, resulting in a huge security flaw: anyone would know how to create a valid JWT for your application.
Is it a big problem to be possible to see your admin-related UI, even without any data? Considering that all of the routes which can return sensitive data are protected by JWT authorization, if a user access any pages or parts of your UI which require data, they would trigger a request to retrieve it, which would probably return a 401 (Unauthorized) HTTP status, or similar. A common front-end practice in these situations is to erase client user data, and redirect to a login page.
So, a typical flow would be:
User inserts a fake access token into their storage
User opens an admin page/ui which uses sensitive data in any way (showing, using for any internal logic, etc)
Web app does a request to the API requesting data
API returns a response which will be interpreted as an authorization error
Web app receive the API response, erase user access token and redirect them to its login page
In most cases, this entire flow will happen fast enough to block your user to further interact and explore your web app.
Would be better if you provide more information about your scenario, so anyone could understand if your worries are something that needs to be considered and truly solved. However, in most cases, the behavior above is accepted.
I'm trying to make a user log in just once, and have his information on all the servers. Any changes made to the user's information will instantly be available for all servers. Is this possible to do without having each user "log in" separately for each server?
Sort of like the $_SESSION for php, but for Node.js
Design 1 -
What I think would be best to do, but don't know how to share socket data between servers, perhaps using something like PHP's $_SESSION?
Design 2 -
What I'm currently doing:
User uses socket.emit to main.js
main.js adds user information onto the emit
main.js emits to the appropriate server
Appropriate server emits back to main.js
main.js finally emits back to user
This seems awfully inefficient and feels wrong
If your information is primarily static, you can try something similar to JWT. These are cryptographically signed tokens that your authenticating server can provide and the user can carry around. This token may contain information about the user that you want each server to have available without having the user accessing it.
If it's not, you may be looking into sharing a database across all servers, and have that be the point of synchronization between them.
Updates based on our comments (so they can be removed later):
If you decide to use auto-contained JWT tokens, you don't need to be making trips to the database at all. These tokens will contain all the information required, but it will be transparent to the end user that won't have insight into their contents.
Also, once you understand the JWT standard, you don't necessarily have to work with JSON objects, since it is just the serialization approach that you can switch by another one.
You'd provide one of these tokens to your user on authentication (or whenever required), and then you'd require that user to provide that token to the other servers when requesting information or behavior from them. The token will become your synchronization approach.
I am almost finished with a SPA application using AngularJS and Bootstrap. So far, I got everything working as desired, except for one thing: Proper handling with the users acts on the Browser's back or refresh buttons.
All the sub-pages within the application have buttons/links to the pages the user may switch to. Still, the application should handle properly back and refresh browser buttons. I should add that there is a login process to enter the application.
Also, all the critical information is stored under $rootScope, so everything is lost when the user refreshes and, in some cases, when he acts on the back button the results are not as desirable.
I actually have two questions:
What is the widely accepted standard behavior of applications like mine when browser buttons are acted on? (remember, there is a login process to begin with).
How should I start tackling the implementation of this approach?
One option I was thinking, is to intercept the request, warn the user that the action will log him off, and if the user cancels, force the browser to ignore the request (not sure this is possible).
Client side routing, each view in the application should have a URL. This week allow the browser buttons to work as expected, and gives your users the opportunity to link directly to a view.
The most commonly used client side router for angular is angular ui-router - https://angular-ui.github.io/ui-router
What is the widely accepted standard behavior of applications like
mine when browser buttons are acted on? (remember, there is a login
process to begin with).
If you are using REST services,
Store authentication token in your local storage or in a cookie
When user refresh the page send a request to server and fetch user information
If the request result in 401 then show login screen
This is one of sample applications I have done with this approach.
I've read about Firebase and it looks awesome for what I want to do.
I've read about authentication and how based on rules certain logged-in users are authorized to do different stuff. Al good.
However, I'm unsure about another type of security: how do I make sure that only my own site (using client-side javascript) can talk to my firebase-backend? I'm asking because afaik there's no way to prevent anyone from looking up my firebase endpoint from the client-side code (url pointing to my specific firebase backend) and start using that for god knows what.
This is especially worrisome in situations in which I want to open up writes to the anonymous user role. (e.g: some analytics perhaps)
Any help in clearing my mind on this much appreciated.
Update (May 2021): Thanks to the new feature called Firebase App Check, it is now actually possible to limit calls to your backend service to only those requests coming from iOS, Android and Web apps that are registered in your Firebase project.
You'll typically want to combine this with the user authentication based security that Kato describes below, so that you have another shield against abusive users that do use your app.
In my opinion, this isn't so much a question about Firebase's security as a general discussion of the internet architecture as it stands today. Since the web is an open platform, you can't prevent anyone from visiting a URL (including to your Firebase) any more than you can prevent someone from driving past your house in the real world. If you could, a visitor could still lie about the site of origin and there is no way to stop this either.
Secure your data with authentication. Use the Authorized Domains in Forge to prevent CSRF. Put security rules in place to prevent users from doing things they should not. Most data writes you would use a server to prevent can be accomplished with security rules alone.
This is actually one of the finer qualities of Firebase and API services in general. The client is completely isolated and thus easily replaced or extended. As long as you can prove you're allowed in, and follow the rules, where you call in from is unimportant.
Regarding anonymous access, if you could make them visit only from your site, that still won't stop malicious writes (I can open my JavaScript debugger and write as many times as I want while sitting on your site). Instead, place tight security rules on the format, content, and length of data writable by anonymous users, or save yourself some time and find an existing service to handle your analytics for you, like the ubiquitous Google Analytics.
You can, of course, use a server as an intermediary as you would with any data store. This is useful for some advanced kinds of logic that can't be enforced by security rules or trusted to an authenticated user (like advanced game mechanics). But even if you hide Firebase (or any database or service) behind a server to prevent access, the server will still have an API and still face all the same challenges of identifying clients' origins, as long as it's on the web.
Another alternative to anonymous access is to use custom login, which would allow a server to create its own Firebase access tokens (a user wouldn't necessarily have to authenticate for this; the signing of the tokens is completely up to you). This is advantageous because, if the anonymous user misbehaves, the access token can then be revoked (by storing a value in Firebase which is used by the security rules to enforce access).
UPDATE
Firebase now has anonymous authentication built into simple login, no need to use custom login for common use cases here.