In a Vue app I have a login. With email and password I send a POST request against the node express backend. If email and password don't match I send back a 409 HTTP status code with a message: "No access! In my POST fetch block I intercept the status code and check if I didn't get a 200 status. If this is the case, I send an error message. If I have a 200 status code I put the JWT token into a cookie. This works. But to be honest, I find the check for the status code too low.
What approaches are there to check the login response. Are there other approaches? Thanks a lot!
async submit() {
try {
const d = await fetch(config.apiUri + "sign-in", {
method: 'POST',
headers: {'Content-Type': 'application/json'},
credentials: 'omit',
body: JSON.stringify(this.data),
});
const j = await d.json();
if (d.status !== 200) {
this.errorMsg = j.message
console.log(this.errorMsg)
return;
}
accessHelper.setToken(j.token, this.mys);
accessHelper.setAuth = true;
this.$router.push("/");
} catch(err) {
console.log("Something went wrong", err)
}
}
For login use cases most "magic" happens on the server. That includes
hashing and salting the password when it's stored and updated,
hashing and checking the received password during logins
You'd want to lock accounts after a certain number of failed logins
and lock IPs after a certain number of failed logins.
After a successful login you're server sends some kind of authentication information (in your case a JWT), which allows the frontend to access secured endpoints. The frontend can't really know more than the fact that the username / password combination was not correct. Therefore, it's fine to only check for the status code.
This OWASP Cheat Sheet contains some useful information in regards to Authentication.
If you feel uncomfortable with handling logins you could think about using OAUTH with e.g. GitHub and/or authentication services like Firebase Authentication
Related
enter image description here
user = Cookies.get("user")
I can't get access to this road. I used cookies to store user data including the token.
Please I need Help
I think your using Strapi CMS and request method for authenticated roots must be POST not GET here the example :
const {data ,status} = await
axios.post('https://localhost:1337/posts',{
headers : {
Authorization: `Bearer ${token}`
}
});
if(status === 200){
setData(data)
}else{
console.log('eeror')
}
make sure to mark the find method from strapi admin otherwise you will get 403 error in strapi user has jwt not token so make sure the token is the jwt which come from strpai when user login!
So I'm just looking to have a sign in of sorts for the app I'm currently developing. For now there's just one username dbreader, but the user will have to input the password to access the remote database (couchdb) and sync. What would be the best way to check if the password they've provided is correct so that I can return failed to login or login success. Send a sync request to an empty database using the inputted password and see if it throws authentication failed?
You can validate credentials by sending a request to the _session endpoint.
Basically, you create a session cookie. If it fails, you will receive a 401 HTTP Status Code. Otherwise, you will receive an 200 HTTP Status Code with your roles,name and your cookie.
More information can be found in the doc
$.ajax({
url:"http://localhost:5984/_session",
method:"POST",
dataType:"json",
data: {
name:"test",
password:"test"
}
}).done(function(res){
console.log(JSON.stringify(res));
}).fail(function(err){
console.log(JSON.stringify(err));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I am using auth0.
My app requires users to confirm their email.
When a user registers, he receives this alert:
Error: unauthorized. Check the console for further details.
This is because the user has not yet verified his email.
How do I "catch" this event / alert in order to redirect the user to a view of my choice?
Thank you for your help
There is a couple of different parts to this.
1). have you enabled the email verified rule? (it is a template available from Auth0 dashboard -
function forceEmailVerification(user, context, callback) {
console.log("force-email-verification");
if(context.connection !== "MyDB") {
return callback(null, user, context);
}
if (!user.email_verified) {
return callback(new UnauthorizedError('Please verify your email before logging in.'));
} else {
return callback(null, user, context);
}
}
That effectively raises an exception in the Rules pipeline if email not verified. It will return the error to your application on the callbackUrl you provide as two query params - error and error_description. It is then up to you how you handle this - Here is a sample Node.js application I wrote specifically to illustrate how this works - In the sample, i am using some express middleware to check for the error and error_description and forward to a Custom controller / view if detected.
2). Only if needed, you can also explicitly trigger an email verification email. It is a POST request to https://{{tenant}}.auth0.com/api/users/{{user_id}}/send_verification_email
endpoint, passing an Authorization Bearer header with an Auth0 APIv1 token (and empty body). The token can be obtained by making a POST request to https://{{tenant}}.auth0.com/oauth/token endpoint passing body of the form:
{
"client_id": "{GLOBAL CLIENT ID}",
"client_secret": "{GLOBAL CLIENT SECRET}",
"grant_type": "client_credentials"
}
You can get the global client id and client secret under account settings -> advanced from Auth0 dashboard. Please do NOT store any secrets on SPA apps etc - using this endpoint should only be done from Client Confidential / Trusted applications (e.g traditional MVC webapp you own).
Hope this helps. Please leave comments if anything unclear.
I'm using auth0 to authenticate my logins to my Single Page App (built on React). I'm mostly using the base API calls (listed here).
The process I'm using is:
get username/email and password when the user enters them on my app's login page
Send a POST request to /oauth/ro with those values - here is that code:
export const login = (params, err) => {
if (err) return err
const {email, password} = params
const {AUTH0_CLIENT_ID, AUTH0_DOMAIN} = process.env
return fetch(`${AUTH0_DOMAIN}/oauth/ro`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
'client_id': AUTH0_CLIENT_ID,
'username': email,
'password': password,
'connection': 'Username-Password-Authentication',
'grant_type': 'password',
'scope': 'openid',
'device': '',
'id_token': ''
})
})
.then(response => response.json())
.then(json => {
const {id_token, access_token} = json
setCookieValue('id_token', id_token) // utility function I wrote
return getProfile(access_token)
.then(data => {
const {user_id, email: emailAddress, picture, name} = data
return {id_token, user_id, emailAddress, picture, name}
})
})
.catch(error => console.log(`ERROR: ${error}`))
}
This is all sent through Redux and the user is logged in (assuming the username/password was correct).
However, I'm trying to figure out how to persist the login when refreshing the page/coming back to the app. I'm saving the id_token (which is a JWT) in the browser's cookies and can fetch this when the app renders server-side. I can decode the JWT and get the payload (sub is the user ID from auth0). However, to get the profile data I need the access_token which Auth0 provides when using the /oauth/ro POST request. Obviously, if the JWT token has expired then it will just reject it and keep the user logged out.
Here is my code to decode the JWT (happens on app render):
const ID_TOKEN = req.cookies.id_token || false
if (ID_TOKEN) {
verifyJwt(ID_TOKEN, (err, decoded) => {
if (err) { console.log(`JWT Verification error: ${err}`) }
else {
const {sub} = decoded
getProfile(sub).then(data => store.dispatch(fetchUserDetails(data))) // fails as `sub` (the user id) is not the `access_token` which it requires
}
})
}
I have tried using the /oauth/ro call again, but this time specifying "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer" and using the id_token retrieved from the cookies, and specifying a device. However, when I do this call, I get this error from Auth0:
{
"error": "invalid_request",
"error_description": "there is not an associated public key for specified client_id/user_id/device"
}
So my question is, what API call do I need to make to get the access_token from the id_token JWT?
Also, as a bonus - when I do the POST request to login, the password is being transfered over plaintext. How would I encrypt this when sending to auth0 so they can decrypt it back? I assume it involves using the client_secret which auth0 provide but I'm not sure how to go about doing that.
The ability to refresh a token programmatically without any type of user interaction is accomplished through the use of refresh tokens. However, this is not applicable for browser-based applications because refresh tokens are long-lived credentials and the storage characteristics for browsers would place them at a too bigger risk of being leaked.
If you want to continue to use the resource owner password credentials grant you can choose to ask the user to input the credentials again when the tokens expire. As an alternative, upon authentication you can obtain the required user information and initiate an application specific session. This could be achieved by having your server-side logic create an application specific session identifier or JWT.
You can also stop using the resource owner password credentials grant and redirect the user to an Auth0 authentication page that besides returning the tokens to your application would also maintain an authenticated session for the user, meaning that when the tokens expired and your application redirected again to Auth0, the user might not need to manual reenter credentials because the Auth0 session is still valid.
In relation to the password being sent in plaintext; the resource owner endpoint relies on HTTPS so the data is encrypted at the protocol level. You must also use HTTPS within your own application for any type of communication that includes user credentials of any kind.
Also note that you can control what's returned within the ID token through the use of scopes, depending on the amount of information in question you might not even need to make additional calls to get the user profiles if you signal that you want that information to be contained within the ID token itself.
I have two applications, both on Nodejs. One front-end and other back-end.
My back-end app is protected with token access using express-jwt and jsonwebtoken middlewares.
My problem is: I am making a request from front-end to back-end passing the token on header, back-end accepts the request and respond properly. Then in the front-end I redirect the response to an specific page (res.redirect('/')), in that moment I get the error UnauthorizedError: No authorization token was found
My front-end request:
/* Authentication */
router.post('/', function(req, res, next) {
// request login service
request({
uri: env.getUrl() + "/user",
method: 'POST',
timeout: 10000,
headers: {
'Authorization': 'Bearer '.concat(global.token)
},
form: { login : req.body.login, pwd : req.body.pwd }
}, function(error, response, body){
if(error) {
logger.error(error);
res.render("error", {message: "Error getting user" });
}
else {
if(body){
req.session.usuario = JSON.parse(body);
res.redirect("/");
} else {
res.render("login", {message: "Login Failed" });
}
}
});
});
I don't know why this happen. Could you help me?
Thanks in advance.
A redirect (via res.redirect) issues a new HTTP request. This means that the Authorization header is empty. This results in the UnauthorizedError error.
To fix this, you have two options:
1. Pass the token in the URI
You can issue the redirect with the token passed in the URL in this way:
res.redirect("/?access_token=" + global.token);
2. Set the header before the redirect
You can set the 'Authorization' header before making the redirect request:
req.session.access_token = global.token;
Problem found.
Anytime the my front-end app makes a request to the back-end side (api) the user logged in front-end is validated against back-end and so the fron-end's session is updated as well. Which means that every request is actually two requests:
One as the real request the app is doing.
The request validating the user logged on front-end in order to be sure that user exists.
This update (second point) was made without providing a token.