I have a REST server over SSL.
Initially, the client logs in with the credentials.
To avoid sending the username/password for each request, I have created a custom token which is returned to the user in the login procedure.
This token contains some information about the client (IP and user-agent) as well as an expiration time; and of course the token is sent encrypted.
Further calls include the token in a custom header field; which are verified in IDispatchMessageInspector
The approach works fine, but I am pretty sure it's not a good approach.
Is there any benefit in using custom authentication than the message inspection?
Message inspection is the checking, changing, and replacing of messages after they are received and before they are sent.
Custom authentication requires the authentication of a username and password, which is more suitable for login or other situations where a username and password are required.
Both types of verification have their own applications.As you said to avoid sending the username and password every time you can choose message inspection. Personal words also tend to be message inspection.
Related
I'm building a REST API using Elixir's Phoenix framework. In the API, I need to authenticate the user by phone number i.e., via sending an SMS OTP code. After authenticating the user, the Auth server sends the Access token and Refresh token to the client. The client(mobile app) stores those tokens locally and sends the Access token in the HTTP header as Authorization: Bearer <Access_Token> in every request to resource server. My actual question is, how do resource server validates the Access token that is received from the mobile app/client?
Does resource server needs to contact Auth server to validate the Access Token? That would a lot of overhead. Please help me understand RestFull API Authentication.
Thanks for taking the time to read my question.
It sounds like you have everything working up to validating the token. You are going to need the public key for the server that signed the token. It depends on what auth server you're working with on how you get that. In some cases you may be able to preload this key as a configuration setting on your backend. Otherwise you can probably get it via https request to the auth server. Most auth servers these days I expect to provide a JWKS api that you can use to get the keys you need. Then with the token and the public key you can use your elixir jwt library to validate that the token you have was signed by the server you trust, meaning the SMS code was validated, and you can proceed with whatever is needed in the backend to handle the request.
If you're using Joken for elixir you can review https://hexdocs.pm/joken_jwks/introduction.html and https://hexdocs.pm/joken/introduction.html for more information.
how do resource server validates the Access token that is received from the mobile app/client?
The same way a nightclub bouncer verifies your driving license as proof-of-age to let you in: by validating the authority and signatures, but it does not need to phone-up your DMV to verify that your license is real because it trusts the signatures (in this case, cryptographic signatures).
That said, some systems do use "reference tokens" which are short (say 32 bytes) of meaningless random data which are used as an unpredictable record identifier for some user-permissions record held by the authorization server. The resource-server will need to contact the auth server initially, but then it can simply cache the auth result itself for some time window.
For token based authentication for any service, first we have to send username/password in the request. Doesn't this cause security issue? How can we overcome this security issue of passing username/password?
The initial request which contains the username and password is no more or less secure than subsequent requests which would instead be bearing some sort of token. The solution to this problem, really to sending any type of information across the network, is to use two way SSL/HTTPS. With HTTPS, information being sent gets encrypted on the client machine, and then (in theory) only the server would be able to read what is contained. So, sending the plain text username and password might seem insecure, but if using HTTPS, then in fact it is secure.
I want to build a REST API which will be used by both mobile app and also a website. I was wondering how would I go about implementing a simple login system for users?
For a simple website, after checking the username and password, one could set a SESSION variable and have the user "logged in".
Now, REST is stateless so I suspect that the above is not the way to go about. I thought that a possible solution would be to have the server generate and return an access token each time the user logs in, and the client will need to attach this access token to every subsequent request to access protected endpoints.
Is the above a viable solution or what is the industry standard for something like this?
(I found OAuth 2.0 to be overkill, but I could be wrong)
There are several token authentication schemes, but if you're looking for the industry standard, then JWT (JSON Web Token) is the way to go. Here's how the process usually goes:
Client sends his credentials (e.g. username and password) to the server.
The server verifies that the credentials are correct, generates a JWT and returns it to the client. Client saves the token in e.g. localStorage.
For each subsequent request, the client will attach the JWT as a part of the request (usually in the "Authorization" header).
Server will be able to decode the JWT and decide if the client should have access to the requested resource.
Now, some interesting features of JWT come from the fact that there is data encoded in it. Some of it everyone can decode, and some only the server can decode.
So, for example, you could encode the user's id and profile picture in the JWT so that the client can use the data from it, not having to do another request to the server to get his profile.
JWT has embedded info about expiration. The server can set the expiration time.
Another cool thing about JWTs is that they are invalid if changed. Imagine you stole someone's token, but it's expired. You try to change the expire information inside the token to some time in the future, and send it to the server. Server will deem that token invalid, because the contents doesn't match the signature attached, and a valid signature can only be generated by the server.
I'm struggling with the concept of how to design a stateless RESTful authentication API with multi-factor authentication.
Almost by definition, the need of a 2FA requires multiple states; logging in with a username/password, then submitting a "code" (either a TOTP, SMS-code, answer to a verification question, etc). This further implies a finite-state-machine (FSM) of some sort.
As far as I can tell, the only options which exist in order to maintain a stateless mechanism are:
the client must transmit some state information (ex: current FSM state) when submitting data to transition to the next state,
the state must be persisted on the server side,
the client must transmit ALL data at every request which allowed it to reach the current state
Obviously transmitting ALL data is nonsensical. So this would imply either transmitting state information (opaque or otherwise) in the request or maintaining state on the server.
Or is there some other technique that I am missing?
I'm adding the solution I came up with in case it is beneficial for someone else in the future. Please note that in this case, PVQ stands for "Personal Validation Question" (ie: Knowledge-Based-Authentication).
At the end, I designed my login endpoint to require:
Authorization header (which is a 2FA token) : Authorization: authType=āPVQā
token=ā<tokenid>ā
username
password
If the Authorization header is missing, the endpoint returns a 401 and sets a WWW-Authenticate header, indicating that a 2FA token (ie: Authorization header) is required to login. param could be PVQ, SMS, TOTP, etc (based on the user's configuration)
WWW-Authenticate : authType="PVQ"
If the client receives a 401/WWW-Authenticate response, it is its responsibility to call the 2FA endpoints:
challenge/get (receive a challenge token)
Client: sends username/password
Server: Responds with an ID, and either
a question (PVQ),
or just sends sends an SMS code via 3rd party SMS provider
challenge/verify (receive the 2FA Token needed for the Authorization header)
Client: sends
ID received in the challenge/get
username/password
response to the challenge (ie: text answer to a PVQ, or SMS code, or TOTP code)
Server: returns
2FA token value
The client can now call the login endpoint with the required: username/password/Authentication token.
In the end, there is not "state" per say that the client returns to the server, but the tradeoff for this, is that the username/password combination must be sent to every request for the 2FA subsystem.
On the server side, there is some state information stored in the DB in the context of the SMS code or PVQ question that was sent to the user, as well as an ephemeral Authentication 2FA token (single use, and fixed TTL).
I am developing a web service and I need to send a username and password to the service in a GET method. Is it OK to send this information in the uri as long as it's going over a secure channel like ssl? In other words, can I have a uri that looks like /users/{username}/{cleartext_password}?
Edit: Sorry, I think I was unclear. The web service is essentially just a database of usernames and hashed passwords. Imagine a desktop application that keeps usernames and passwords in a remote database. The end user types their username and password into the application and the application accesses the web service to authenticate the user.
So, the application will need to send an end user's username and plaintext password to the service. The service will take the username and password and check that the username and the hash of the password match the username and hashed password in the database. The application itself will have to authenticate before it can access the service, but I am just wondering what is the best way to send the end user's username and password to the service for authenticating the end user. I don't to use a POST method because I am simply authenticating and therefore not changing the state of the server. Sorry for the confusion.
Do this.
Send a "key" and a "digest".
The "key" is equivalent to a username.
The "digest" is a SHA1 (or MD5) hash of the key, the URI and a "shared secret" or password.
When the server gets this, it computes it's own version of the digest, based on key, URI being requested and the "shared secret" or password. Failure to match digests is a 401 error response.
If it's going over a secure channel, there's no problem sending the username and password as cleartext. I'd just recommend against ever sending them as cleartext through an insecure channel and against sending them repeatedly for each request.
What you could do is first authenticate to the web service (send the username and password via ssl as cleartext) and get a token from the server that it will recognize. Then send that token with each subsequent request.
Generally speaking this is not a good idea... This data will be present in a number of log files, consequently the data could be visible to people who should not see it. At the very least you should hash or encrypt it before sending it if you can.
Here is a related discussion for a little more detail... Is an HTTPS query string secure?
SSL does encrypt the URI, but definitely take a look at some alternatives.
HTTP Basic Auth is nice and simple, and well supported by browsers, webservers, etc
It also won't end up in log files to the same degree as URIs
NB: It's just some plain-text HTTP Headers, so definitiely NOT recommended for non-SSL apps.
http://en.wikipedia.org/wiki/Basic_access_authentication