How does JWT do Authentication - javascript

JWT official docs say that JWT is most commonly used for Authentication.
Authentication is the process of determining whether someone or something is, in fact, who or what it is declared to be.
Now if my server gets a request from the client and header of that request contains JWT. I will validate the JWT token with my secret key.
If the token is valid, I can say for sure that:
That token was generated by my server.
At the time of generating token user had provided their correct credentials. Meaning, if user claimed to be John123, they provided correct password for John123 (server verified this, otherwise server return error response).
If the token is valid, what I can NOT say for sure:
On subsequent requests, if the user is claiming to John123 (by passing {userid:John123} in request body) and they provide us with valid JWT, I can't say for sure that their claim is correct. Because its possible that user Alice123 went into the localstorage of John123 and stole the token and set it into their localstorage.
Now my question is how does JWT really validate that the users actually are what they are claiming to be. What I am missing here? Do I need to keep a mapping of JWT, userid and ip of client.

Well one step you are missing is that even after verifying the authenticity and claims (e.g. expiration date) of an incoming JWT, you still probably would have to hit your user database to make sure that the account is active and still exists. So a JWT does not by itself solve the entire problem.
Regarding your actual question at the end, you generally have no idea about who the bearer of the JWT really is. If Alice steals John's phone, then in fact she may be able to masquerade as him. But keep in mind, if she does something this drastic, then she probably also has his credit and bank cards, and maybe some other passwords too. No authentication process is completely safe.
With regard to lesser forms of theft, JWT is still robust. For example, if someone tries to setup a man-in-the-middle attack to sniff your JWT, it won't work assuming your app encrypts that JWT with SSL. And the real reason for JWT of course is that they are already signed with a key only known by the server to prevent the bearers from tampering with them.

JWT does not validate if the users are what they claim to be, because JWT is not an authentication framework. If you use JWT as an access token, you/your authentication middleware should make sure only to rely on the information in the token itself to identify the user and not any information in the request body.
Ususally you would store the user id or name in the token. The subclaim can be used for that.
The "sub" (subject) claim identifies the principal that is the
subject of the JWT. The claims in a JWT are normally statements
about the subject.
The authentication middleware ususally only verifies, that the JWT itself has not been modified. But you won't recognize if Alice uses John's token.

Related

How can the backend know if the request is coming from the same machine the firebase user logged in on?

I'm a little unclear on part of the Firebase auth flow.
I'm using the prebuilt ui to sign a user in on the web frontend, and after that's completed I'm using this, partially pseudo-coded:
signInSuccessWithAuthResult: async function(authResult, redirectUrl) {
const idToken = await authResult.user.getIdToken();
setIdTokenAsCookie(idToken);
reloadPage();
}
The idea is that the user has signed in, so I set the idToken as a cookie and refresh the page. The backend gets the idToken from the cookie, then checks Firebase to validate the idToken there, and returns the logged-in page with user-specific data.
But....how does the backend know that this request came from the machine the user logged-in on? Couldn't an attacker on another computer send a request with a brute-force guessed idtoken and thus gain access? Is it a matter of rate-limiting the endpoint on my backend to prevent them finding a valid idtoken?
But....how does the backend know that this request came from the machine the user logged-in on?
It doesn't, and that's not required.
Couldn't an attacker on another computer send a request with a brute-force guessed idtoken and thus gain access?
That is astronomically unlikely to happen. If this is what you're worried about, you're worried about things that are normally considered cryptographically secure. The idToken you get from Auth is a JWT. Read more about that.
Is it a matter of rate-limiting the endpoint on my backend to prevent them finding a valid idtoken?
I would consider this a waste of effort.

How should I encrypt passwords for API access without showing off the algorithm to the client?

I have a REST API (.net) which for the initial login requires the password to be encrypted (RSA with OAEP). The reason was to obscure the users passwords from local logs.
Performing this encryption with javascript is complicated and I would need to let the client know the public key. The end user would be able to reverse engineer the encryption method then could use it to brute-force (or worse) access. So why bother, right (it is SSL Secure).
Thing is, I still need that password to be encrypted. Should I have some sort of encryption service at the server side that gives me the password to throw at the token endpoint? Why not have the service just log in for me then return the token. How should I proceed?
Thanks ^_^
This seems like a general authentication question. You can solve it like you would solve user authentication. Think of it this way:
When a user signs-in into your app, they provide their data on the client, and then it is validated on the server. In order for them to stay logged in, they get some sort of token, either via a Cookie session, JWT or whatever. Which is then saved on the client and sent on each request to the server in order to verify they are authenticated.
The above is how websites can show "registered users only" content. By validating a previously given token on each new request.
Now, applying this method to your REST Api. A user needs to request a token (which should not be your master password, but a uniquely generated one, in a per-user basis), and then save it locally for X amount of time. Every time the user makes a request to the API they send that token, which is validated.
This is also how normal APIs do it. You will need a token or some sort either way. If it's really sensitive information you're showing, the token should update every now and then (from minutes to days depending on how sensitive). You keep a record of valid tokens in your server. That way, if any token is "stolen", then it will only be valid for a small amount of time.

Whats the best practice for storing Basic Auth password?

Let's say I'm trying to build a web application using Vue.js where an end user uses a form to subscribe to a newsletter.
The frontend is a Vue app, the backend is a PHP REST API.
The API requires Basic Auth authentication.
In the frontend I'm calling the API using axios:
axios
.post('localhost/api/v1/subscriber.php', {
// I know the data is missing but this is not what the question is about..
auth: {
username: 'USER',
password: 'PASS'
}
})
Everything is working fine, except that Vue.js is JavaScript and therefore visible on the client side (right click -> Inspect/ View page source) and every end user can see the username and password.
What's the best practice for "storing" the password (and username)?
Even if PASS was the hashed password, the end user would still be able to use it to to an API call by himself...
From my point of view you have a fundamental design issue with your API. As it seems you want to expose some global credentials to the frontend so the SPA can in turn authenticate against the API. This approach is strange: either the endpoint is public and therefore should not need authentication or it is protected and each user should authenticate properly.
If you just want to protect the API against spam bots etc. you could send a nonce to the app and check for it in the subsequent request. This by no means is a robust protection but makes sure that each POST requires a GET and some parsing on the spammer's side.
If you want your users to be authenticated across multiple requests you should use well established methods to provide a session or a remember-me function. This could be e.g. session cookies (works but is vulnerable against CSRF attacks), JWT (with or without OAuth) or something similar.
But whatever you do: don't try to obfuscate shared credentials you pass around!
As a best practice, you shouldn't store password. You should create a JWT token on the backend when the user logged in or signed up. Then you can store the JWT token on your front-end(local storage) when you received the token from the back-end.
Easy Way to Encryption,
You can encrypt your password with any encryption algorithm on client-side then decrypt on the back-end with the same key.
Hard Way to Encryption,
As a hard way, for security reasons and security best practices, you should encrypt all your request end to end. Otherwise, anyone can access the user's information on public networks.
The below link includes all detailed information about the end to end encryption
https://medium.com/#weblab_tech/encrypted-client-server-communication-protection-of-privacy-and-integrity-with-aes-and-rsa-in-c7b180fe614e
You can store your Authorization header values in localStorage or sessionStorage.
Use interceptors to include the header values for each of your request
Here is sample:
axiosInstance.interceptors.request.use(function (config) {
const token = localStorage.getItem('token')
config.headers.Authorization = token
return config;
});
The value of Authorization header, stored in LocalStorage, will be automatically each time you make HTTP requests.
Note: Replace the variable token with username and password

How to use a JWT token as login validation?

I'm making a login page and I've found that JWT tokens are preferred over sessions but I don't understand what to do with a token.
I send user and password uncrypted with ajax to server and validate the user in a php file which then returns a JWT.
What should I put in my JWT? Do I only check for a token to know if the user is logged in or do I process it somehow to check if it's the right token? If so, how?
So far I've seen examples on client side where you only check if token exists but why should I have hashed data as token instead of a 1 or a 0. I don't get the advantages of this method.
EDIT: Should I both request a JWT token which I store in session storage and store what the user types in the log in field also in session storage and then compare them with eachother every time the user reloads the page?
Looks like we need basics of how JWT works here:
The client sends username/password to the server using ajax.
The server checks username/password and if they are valid, creates an encrypted token, which the only server can read and understand.
Server takes into account various fields (also known as "Claims") like "iss" (token issuer) and "Sub" (Subject of token), whole list here.
We can custom fields like user-id which can be used later while validating token.
Server sends token back to client through response. Client saves this token in local storage or some variable.
With each further request, client sends this token as header.
Server examines and validates this token, gets require info from this token like user-id and responds to the user appropriately if valid. Token may also contain expiry date/time, so after a certain time, the server may choose to refuse to serve a client.
While this may not directly answer your question, it clarifies basic workflow of GWT.

How do I securely use a REST API solely from within a web browser?

I'm trying to find a way to interact securely with an OAuth (draft v2-23) API completely in the browser. There are obvious security concerns with authenticating in the browser because the auth token and other keys are exposed somewhere in the browser.
Is there a secure way to hide those keys, or am I limited to creating a server side solution that keeps track of those keys?
I came across this very concern when working with the mobile version of my application (since a normal login auth wouldn't work.)
The solution I came up with is to work with 2 keys. When the user logs in, they are initially given their token. The client already has the token saved as a variable in the app (you can make the token whatever string you want, I usually generate a base64 key of 32 length.)
So this is the basic play by play of what happens when they call the server from a GET/PUT/etc..
Send request with USER TOKEN and SERVER TOKEN as parameters.
SERVER TOKEN is checked against the server token (which is salted and hashed). (If SERVER TOKEN is good, proceed to step 3, else deny request here.
USER TOKEN is checked against the user token assigned to said user (which is salted and hashed) and makes sure it exists. If good, proceed to step 4, else deny request here.
Execute request (GET/PUT/DEL/POST etc.)
Long story short, i keep a salted and hashed version of the user tokens (which are unique to the user) and the server tokens (which is the same for every user) on the server and the de-salting and de-hashing is done on the back end.
I hope this kinda makes sense. It might not be the standard or completely right but it's what i understood token auth to be and this works for me.
If others see something wrong with my reasoning please chime in and tell me so.

Categories

Resources