I'm working on a RESTful web application. I would like to have user registration occur via a POST request (username and password in the request body), and user login via a GET request (username and password in the query).
The PassportJS documentation seems to show that Passport expects credentials to be in the request body (which it parses). I don't quite understand how it would work with GET requests, since they don't have bodies (typically, if I understand correctly).
How would I make this work? Is this a bad idea? If it is, is there a RESTful alternative?
Yes, this is a bad idea. GET requests go into browser history and server log files, are visible in the address bar, can be cached by proxies, etc. This violates both HTTP semantics and security. Just do login as per industry best practices and save your energy for building your actual application. If it gives you warm fuzzies, you can think of a login being a CREATE operation for a session resource, which is done via a POST request according to REST.
Related
Just started looking a JWT and the examples I have seen first require the user to do a POST request with the body of the request containing the username and password in plain text.
After this request has been authenticated, a JWT is sent which is then used is further requests.
Clearly I am missing something here but have I not just sent unsecure data on my first request? Is this where I would need HTTPS?
JWT doesn't give you security out of the box it's main point is to make sure that the Token wasn't changed by untrusted authority. It just verifies that the data inside is correct.
However, the JWT itself, the data block of it is readable by anyone, you can just parse it on the client, and read the userName / email / from it, if you want to, so an attacker could read it too, if the data block itself is not encrypted.
HTTPS would encrypt all the data wich is passed between client <-> server. It has nothing to do with authentication, its just a protocol, you should use it anyway, either with JWT or not.
JWT are used for authenticating a user that already authenticated himself to the server before, and are really useful in stateless environments, not really in stateful environments.
The purpose of JWT is to store enough data on the user, so that the server that receives it can use it to decide if the user is legit and what he can do. They are really useful in distributed environments, because then you can just pass the JWT from one server to another, and as long as they all hold the signing key, they will be able to authenticate the user only based on the token.
The username and password are only required for the server in the first request, so the server can authenticate the user against a database of users for example, and then, every request after will use the token, making the server to be able to authenticate the user without another round trip to the database on every request.
As far as HTTPS goes, I would say - use it for everything. In today's wireless networks everywhere, your data is much more exposed than before.
I'm working on a project based on Phalcon which consists in two different stand-alone subprojects: a php + angular frontend and a php REST API.
I protected the API with OAuth2, using PhpLeague OAuth2 Server. The API server is the OAuth2's authorization server AND resource server.
This is the actual flow:
The user can browse the public endpoints of the frontend, and when hits a private page, gets redirected to the login page;
The login page has username and password, POSTs them to the frontend server;
The frontend server calls a public method on the API server, which is expecting a Password Credential Grant: it validates the credentials and sends back an access token and a refresh token;
The frontend server caches both the access and refresh token in session and uses it for some API calls: the first of those is the '/users/me', which gets info about the current user and its ACL on the frontend sections;
The frontend server sends the page to the browser, which loads its javascript files.
Now, OAuth2 states that access tokens should be short-lived and refresh-token should be long-lived: in the frontend server logic, the API calls which receives a 401 (caused by the expired access token) are retried by sending first the refresh token to obtain a new access token via a Refresh Token Grant. If this second call is rejected, I assume the user is no more logged in (refresh token expired / revoked).
The pages are using Angular to perform data and ux/ui management. My question is:
should the Angular code call directly the API server?
Actually the first thing my javascript code does is to get a config object from the frontend server, which contains the access token too, and uses it to make the calls to the API server. The problem with this is that i should rewrite again the "refresh token logic" in javascript (after it expires, i get 401s), and by what I have read on the subject i understood that it is better to not make the refresh token visible to the client (as it can generate new access tokens).
So i was thinking about a "two step approach", where every javascript API call goes to an endpoint on the frontend server which relays it to the API server, but this is obviously slower (JS -> FRONTEND -> API and API -> FRONTEND -> JS).
What is the correct approach? It's not very clear to me if the frontend should be considered as two clients (php + js) which should work separately or not, as I imagine that an hypothetical iOS app would be making calls 100% against the API server.
I have used the same approach in my own projects. The problem that we have is that the client is not secure. In order to generate / refresh a token, you need to pass secure information to the authorization server.
I have done the same as you basically, let the back-end handle the tokens and their temporary storage. You cannot and should not trust the client with important information which lets you generate tokens. In terms of delays, I wouldn't worry about it too much since you're not going to be doing that much extra work, you won't even notice the delays. I have a system like this built and used by hundreds of thousands of users with absolutely no issues.
Now, you have said a few things in here which make me wonder what you are doing.
OAuth2 is not a user authentication system, it's an application authentication system. You don't pass a user and their password and generate a token for them, you pass a ClientID and ClientSecret and they generate a token for you. Then you have an endpoint which gives you the user details for this user, you pass your userid or username and get the details of that user.
A token expired does not mean your user is logged out. Those are two completely different things. How are you going to expire a token for example, when your user wants to log out? You can't, your token will still be valid until it expires after the set amount of time has passed.
A token can be used for let's say half an hour, but your user may use the website for 1 hour. So before you hit any API endpoint, you could check ... has this token expired yet? if yes then you can go and refresh it and keep working without having to bother your user with a new login screen.
The whole point of an OAuth2 system is to make sure that only authorised clients can access it. A client is not a user, it's an application. You can have a website for example and you only want users of that website to access your API.
You can have endpoints like ValidateUser for example, where you take a username and a password and return a yes or no and then you log your user in based on that.
Irrespective of language/framework, second approach is secure and better than first one because to get access token by providing refresh token to Authorization server, it still requires Client ID and Secret which should never be passed to Browser for security reasons.
In first approach, to make a direct call it will not work if your Authz Server is hosted on different domain than your frontend server because of Same Origin policy of browsers. Even if they are on same domain, still you are exposing Client ID and Secret which will compromise your frontend server
I'm a regular reader here at stack overflow but this is my first question.
I'm developing an authorization-server using the OAuth2 specs. And I just got stuck with how do I ensure the first-party client authenticity while using the password flow. I read many forums and this is what I got:
Javascript single-page clients
This blog post by Alex Bilbie, he states that to avoid the client_secret problem we should just:
It’s simple; proxy all of your API calls via a thin server side component. This component (let’s just call it a proxy from here on)
will authenticate ajax requests from the user’s session. The access
and refresh tokens can be stored in an encrypted form in a cookie
which only the proxy can decrypt. The application client credentials
will also be hardcoded into the proxy so they’re not publicly
accessible either.
But now this proxy can be accessed by someone impersonating my
angular app. And then I came across this blog post from Andy
Fielder: How Secure is the OAuth2 Resourc Owner Password Flow
for Single Page Apps. He basically says to rely on CORS to
avoid impersonating JS clients.
It is a good idea to use both approaches to secure my JS app?
Native Apps (Desktop and Mobile)
In the case of mobile apps, I only found cases for Authorization
Code and Implicit flows. This is not what I want, as the redirects
will compromise the user experience. So my thoughts on this is:
I will use the ROP flow and then register the client with a
client_id generated for this particular installation and attach it
to the user account, receiving the access_token and a
client_secret as response. Any other token request made by this
client MUST carry this credentials (as the client_id is specific
for the installation, I will be able to check if this client is
already authenticated). This way if someone uses any credential for
impersonating a client, or even registers a bogus client, I can take
mesures to revoke the user and client access.
I know that this can be overthinking, and I also know that some of this matters doesn't avoid anything. I just feel that is my job to protect my API as much as I can.
I would really appreciate your thoughts about this matters! Am I really overthinking? Should I just use the concept of a 'public client' and carry on?
Thank you all and happy coding!
First of all, this problem is not a common priority because most applications are developed first with website, and after with the API. This is probably the reason because no one knows how to deal first clients with oauth2, because everyone have developed other ways to do that and oauth2 is needed only to grant user access to third party applications.
Even if you have develop the oauth2 authorization server only for your first clients applications (thinking about a single authentication mechanism instead of developing many), you should try to develop the authorization code or implicit grant types. You will realize that you need a way to check what user is actually logged in.
The two common methods are:
user session (based on Cookies)
user access from localStorage (based javascript)
In either ways you need to check your application security, user session is vulnerable to CSRF, localStorage are vulnerable to XSS. There are a lot of articles about how to secure your website against either, so I will not suggest anything here, you just need to know that they exist.
Now that you choose your authentication method we can start to do some consideration about:
Javascript single pages applications
Proxy
Having a proxy that filter all requests in my opinion is like to have a door with the keys always inserted. It's useless even build the door.
However, for session based authentication it's the only way to do it. Allowing session authentication on your Rest API will open to CSRF security issues, so you need to have a proxy layer that get the user session, retrieve the access token from the session and do the request to the Rest API adding the Authorization header.
CORS
With this method you need to store the user access token in the localStorage, because the token is retrieved from the Js client directly.
Using CORS you are sure that other websites cannot do requests to your Rest API from a browser. But your first client need to be public (ie: it does not have a client_secret).
Native Apps (Desktop and Mobile)
In my first application I tried to use the same mechanism that you suggest to secure the auth flow. However that type of mechanism require that you identify every user client in an unique way. This is not possible in iOS for privacy reasons and with some probability it will denied in the future releases of Android. So you should rely on a public client and add only the client_id in your native application code.
This means that your native app client/your js client can be impersonalized? Yes, and there is no way to prevent this with oAuth2 resource owner password credentials grant type.
The main reason about this is because oAuth2 is not for authentication, only for third-party authorization, and that grant type was added only for specific third-party applications trusted enought to use directly the user password. You could read more about this argument here and here.
At the end
You still need a way to auhorize your user, and I think that the best you can achieve using oAuth2 is what Auth0 did.
Essentially this Saas manage your users with an oAuth2 server + OpenID connect, so you are always managing your users like its a third-party application and everything works fine.
Indeed, you can see on this page that for mobile applications they suggest to use a browser based login form, because the native one can be impersonalized by everyone that decompile your application, but if you wrap it into an authorization code flow it works fine.
I am developing a Chrome extension which will be sending data via an AJAX request using jQuery. I need to ensure though that only the logged in user has send the request. This might not be the right approach trying to secure the AJAX request itself so any advice is appriciated.
you cannot secure Ajax requests on client side as every one can request to your APIs if it's included in your JS.
but there are some workarounds which you can choose to have more secure interact with your server:
you can send encrypted data
you can also obfuscate your code to make it much harder to read
use SSL to protect data from snoopers
EDIT:
as you mentioned if you want to make sure a user is logged in to do something you can use encrypted cookie and a token as mentioned in another answer. but if you want to prevent requests and not rejecting them maybe above solutions will help you.
To make this work, when the user logs in, you need to set a cookie that contains some sort of authentication token or session ID (usually some unpredictable string of characters) that is also stored on your server.
Your Ajax request can then include that authentication token from the current browser's cookie as a parameter of the ajax call and your server can then authenticate that the token belongs to a legitimate user.
If the user is not logged in, there will be no cookie and thus no token.
I'm hacking together a script to automate the submission of tickets to our helpdesk system. So far it's a very simple, but working system. I have a page with a form that auto-submits via JavaScript with form value based on the URL requested.
This works great when you access the page from your browser. Assuming you're already authenticated to the ticket system page, the auto-submitted form happily sends its form data and you are directed to the ticket list where you see the newly auto-submitted ticket. Unfortunately of course, the ticket system is an HTTPS secured site, so if you're not logged in you're directed to the login page and the auto-submission fails.
The idea however is to run this auto-submission on a schedule, or kick it off remotely, where the initiator won't necessarily be human and won't be following the form submission to babysit it with delicious authentication cookies.
So, being a newbie in this area, my options seem to be A) dive in and get real messy by listening for the auto-submission response, determine whether the login page is being returned and submit some credentials via JS (not a huge deal as this automation would run solely on a secured server), then resubmit the form... or B) somehow do this the proper way by authenticating beforehand. But that's where my knowledge ends.
I've read through this similar question, but am still coming up short. Is this proper automation only possible if the server in question supports some form of auth token API? Is there not a more direct way to connect and request/submit data to an HTTPS site? I've been glossing over some introductions to cURL, but have not yet dove in.
NB: I don't have direct access to the ticket database, code, nor to the web server processes/accounts running it. I probably can run processes on the same machine, which is why I'm not real concerned with the security of auto-submitting credentials, but that's probably it.
Firstly, whether your ticket system directs you to a login screen if you're not already authenticated has nothing to do with HTTPS - this will be either a username/password <form> that then sets a cookie, or it will be a WWW-Authenticate header. Each of these can be used whether you are using HTTPS or plain HTTP.
Whichever method it uses, if you're planning on doing this in a web browser, chances are you won't be able to because CORS (cross-origin resource sharing) will probably not have been set up to allow it.
If however you're doing this from a script such as Node.js, Python, PHP or anything else that can make arbitrary HTTP(S) requests, you might want to look at a flow like this:
Request the index page of the ticket system
Detect whether it gave you a login screen
If so, fetch any necessary data from the login screen (e.g. a nonce) and make a POST request as if you filled in the username/password yourself
Check that authentication was successful (based on the POST response)
Keep the cookie returned by your POST request and use it to submit the ticket.
For the simpler case where the system uses a WWW-Authenticate header it would be like this:
Request the index page of the ticket system
Detect the WWW-Authenticate header in the HTTP 401 response received
Send an Authorization header with an appropriate value
Check that authentication was successful (based on getting an HTTP 200 instead of a HTTP 401)
Send the same Authorization header again while submitting the ticket.
Using WWW-Authenticate is described at Wikipedia for basic and digest authentication.