Parse Server how to access token for password reset - javascript

I am using Parse Server and have setup the config options to use a custom page for the password reset. This works fine, when you click the password reset link it takes you to my custom page.
The query parameters on the URL give me the username and a token. My plan was to use the username to query the User Class and get the user, and then get the token associated with the user to see if it matched the token in the URL.
My problem is I can't find where that token is — I do not see it in Parse Dashboard when I browse the User Class. And when I try to access it via a User query it comes back undefined (as I would expect since it's not there).
Here's some example code I put in my React component:
const { token, username } = this.props.queryParams
console.log('username from URL query params: ' + username)
console.log('token from URL query params: ' + token)
const User = Parse.Object.extend('User')
const userQuery = new Parse.Query(User)
userQuery
.equalTo('username', username)
.first()
.then(
function(user) {
console.log('Returned username: ' + user.get('username'))
console.log('Returned token: ' + user.get('token'))
},
function(error) {
console.log('Error:')
console.log(error)
}
)
Which logs this:
username from URL query params: davidhank
token from URL query params: veKHpzVgFEFCHdqfkXphz5DpD
Returned username: davidhank
Returned token: undefined
My question: Where does Parse store this token?

Related

POST request issues to Twitter API

I have been using NextJS, Twitter-lite to build an application using the twitter app, I basically am trying to implement the functionality in which users can post a tweet from the app to their twitter accounts. I have also used Next-Auth for implementing oAuth for twitter.
So after some working, I have managed to make it work and highlight my error - Access tokens. I want to fetch access tokens from the user after they have logged in,
In the below example - I run this script and a post is updated to my account indeed
Here is my code for the api/twitter/post.js
import Twitter from 'twitter-lite';
import { getSession } from 'next-auth/react'
import { getToken } from 'next-auth/jwt';
export default async (req, res) =>{
var Twit = require('twit')
const session = await getSession({ req });
const token = await getToken({
req,
secret: process.env.NEXTAUTH_SECRET
});
console.log(token.twitter.accessToken)
var T = new Twit({
consumer_key: process.env.TWITTER_CONSUMER_KEY,
consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
access_token: 'process.env.TWITTER_ACCESS_TKN',
access_token_secret: 'process.env.TWITTER_ACCESS_TKN_SCRT'
});
T.post('statuses/update', { status: 'hello worldj!' }, function(err, data, response) {
console.log(data)
})
return res.status(200).json({ status: 'ok'});
}
Now this does work, when I hit my api route a new tweet is posted but only to 'my' account because I provided my access_tokens, I would like to know how I can get users access tokens, I have already signed them in using NextAuth so I'm sure I'm just missing a few things.
So I figured this one out,
In the call backs functions in the [...nextauth].js, I was just fetching the access_tokens with an outdated name and the new name is account.oauth_token
For anyone who ever encounters this issue - (Trying to fetch logged in users access tokens to access restricted twitter endpoints)
callbacks: {
async jwt({ token, user, account = {}, profile, isNewUser }) {
if (account.provider && !token [account.provider]) {
token[account.provider] = {};
}
if(account.oauth_token) {
token[account.provider].accessToken = account.oauth_token;
}
if (account.oauth_token_secret) {
token [account.provider].refreshToken = account.oauth_token_secret;
}
return token
},
This is how you get the logged in users access_token and access_token_secret

How do I pass additional data when calling socket.connect() in socket.io?

I am trying to find a way of passing additional data such as username, avatar_url when connecting to socket when user clicks login. Example:
const logIn = ({ username, avatar }) => {
socket.auth = { username };
socket.connect({ query: { username: username, avatar: avatar } });
}
On the server side:
io.use((socket, next) => {
console.log("===> Data:", socket.request._query);
});
But I do not get any key-value for username and avatar field. I tried searching the documentation but could not find any information for socket.connect() relating to passing data.
How can I pass data in socket.connect()?
Use JWT and pass that data as part of the object.
So the flow would be that when you 'auth' have it send back the JWT with the avitar etc.
When you send it to the server and decode the token you can set that as part of the socket object
As an example ( we currently use the jsonwebtoken package )
// verify token
jwt.verify(token, '[password]', (err, decoded) => {
try{
/* connecting */
socket.avitar = decoded.avitar;
socket.nickname = "nick name";
if(err) return next(err);
//('success!')
Then you can just access it when emitting, because the socket ID is unique to the user it should hold the values, if they disconnect / reconnect the token will still contain the values.
In cluster mode, use redis socket.io and pass this in as an hset to store the data with the socketID

How do i store jsonwebtoken on cookie for front-end so client can send back the token for auth

I've been struggling to do this for about 6 days...
Everything is working perfectly such as authorization but one problem I had is making authentication.
On my user model (for creating the database schema) I do have a way to generate a token for logged in users or registered.
userSchema.methods.generateAuthToken = function(){
const token = jwt.sign({ _id: this._id }, config.get('jwtPrivateKey'));
return token;
}
So when user post to /login, server will respond with a token:
router.post('/', async (req, res) =>{
// Here i'm validating data and then if everything is right the code under will run.
console.log('logged in as: ' + user.username);
// Here i'm using the function to generateAuthToken().
const token = user.generateAuthToken();
console.log("Token from server: " + token);
// now here is my main problem i would like to use cookies to store it for an hour or so.
// then client can send it back to server for protected route.
res.status(200).send(token);
});
I have made a middleware function for auth (to check the token if you're going through a protected route)
module.exports = function (req, res, next){
// instead of using headers i would like to check for the cookie value if it's the token,
// pass the user in, else Access denied.
// I have no idea how to use cookie parser with middleware functions.
const token = req.header('x-auth-token');
if(!token) return res.status(401).send('Access denied. Sign in or register.');
try{
const decoded = jwt.verify(token, config.get('jwtPrivateKey'));
req.user = decoded;
next();
}
catch(err){
res.status(400).send('Invalid Token!');
}
}
here i'm using the auth middleware function:
const express = require('express');
const router = express.Router();
const auth = require('../middleware/auth');
// but it's actually not passing the user in since i haven't done it with cookies.
router.get('/', auth, (req, res) =>{
res.render('index', {});
});
I do know I can do it with localStorage but it's a terrible practice and it would be better to store it on cookies so no one could hack on.
Is there any good approach to solve this problem? I'm kinda lost and lost hope to go back to sessionID (which I don't want to :( ).
After you request on frontend, you need get the response (token) and save on browser using this for example:
fetch('http://your-api-host/login', {
method: 'POST',
body: {
username: "user1",
password: "passworduser"
}
})
.then((res) => res.text((res)))
.then((token) => {
document.cookie = `AUTH_API=${token}`; <-- this save the cookie
})
With this value saved on frontend you need send this information on all requests, it's commum send this value on your HEADER (how you makes), to save on header you need read the value from token and put on header, like this:
const headersTemp = document.cookie.split(';'); // <-- this get all cookies saves and splits them in the array.
const finalHeaders = {};
headersTemp.forEach((header) => { // <-- looping on all cookies
const headerTemp = header.split('='); // <-- split each cookie to get key and value
finalHeaders[headerTemp[0].trim()] = headerTemp[1].trim() // <-- save on object to access using keys.
})
Now you can access all cookies using the key (the same used before), I used the key AUTH_API to save my cookie, let's send the request using fetch api:
fetch('http://your-api-host/route-protected', {
method: 'POST',
headers: {
'x-auth-token': finalHeaders['AUTH_API']
},
})
If you creating your application using libraries how React or any SPA framework, probably you will use tools like Axios, and I recommend uses libraris how This, it's more easy to work with cookies.

Cognito getId: NotAuthorizedException: Invalid login token. Not a valid OpenId Connect identity token

I am new to Cognito (JWT tokens & whole auth thing in general) so pardon me for asking stupid questions. I am trying to use Cognito user pools with identity pools. I logged in a user using the default URL (https://testapi123.auth.us-east-2.amazoncognito.com/login?response_type=token&client_id=<>&scope=openid&redirect_uri=https://aws.amazon.com) and got a token. I am unable to figure out how to get the identity id from this token for use in getId() API. This I want to later use to get credentials from the federated identity pool (not sure if i have that part right either).
For reference, i have my code -
var AWS = require('aws-sdk');
var cognitoidentity = new AWS.CognitoIdentity({apiVersion: '2014-06-30'});
exports.handler = (event, context, callback) => {
// TODO implement
var params = {
IdentityPoolId: 'us-east-2:<xxxxxx>', /* required */
AccountId: 'xxxxxxx',
Logins: {
'cognito-idp.us-east-2.amazonaws.com/us-east-2_xxxxx': '<**identityID???**>',
}
};
cognitoidentity.getId(params, function(err, data) {
if (err) console.log('Error3 : ' + err, err.stack); // an error occurred
else {
console.log('retval:' + JSON.stringify(data)); // successful response
var idenId = data.idenId;
var params = {
IdentityId: idenId,
CustomRoleArn: 'arn:aws:iam::xxxxxxxxx:role/cc_admin',
Logins: {
'CognitoIdentity': 'cognito-idp.us-east-2.amazonaws.com/us-east-2_xxxxxxx'
}
};
cognitoidentity.getCredentialsForIdentity(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
}
});
callback(null, 'Hello from Lambda 1');
};
The error - "2018-06-06T18:59:58.614Z ce0fc216-69bb-11e8-bbfc-4fff0d953dd4 Error3 : NotAuthorizedException: Invalid login token. Token signature invalid. NotAuthorizedException: Invalid login token. Token signature invalid."
I have tried parsing the JWT token received (with jwt.io). It shows me some details but none of them seem to be identity id to be used in the request. I have also tried using the entire token as identity id.
Really need help. Thanks.
First, you only need to pass Identity Pool Id in params for getId function to work. It will return IdentityId associated with your identity pool. Replace
var params = {
IdentityPoolId: 'us-east-2:<xxxxxx>', /* required */
AccountId: 'xxxxxxx',
Logins: {
'cognito-idp.us-east-2.amazonaws.com/us-east-2_xxxxx': '<**identityID???**>',
}
};
with
var params = {
IdentityPoolId: 'us-east-2:<xxxxxx>'
}
Second, you can't create credentials unless you have idToken i.e JWT (JSON Web Token which is returned to client after successful authentication by user pool).
It looks like this..
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
You can get this token only by signing in...Run this command on terminal after configuring aws-cli or use aws-sdk and run function InitiateAuth
aws cognito-idp admin-initiate-auth --user-pool-id ap-south-1_xxxxxxx --client-id AAAAAAAAAAAAAAAAAAAAA --auth-flow ADMIN_NO_SRP_AUTH --auth-parameters USERNAME="abc#123.com",PASSWORD="********"
Finally,Change your params function passing to getCRedentials method 'Logins' key to:
Logins: {
"IdentityId": <result from getId>
"cognito-idp.us-east-2.amazonaws.com/us-east-2_xxxxxxx": <your idToken>
}

NodeJs and nodemailer - hide query parameters in the Email-Link and URL?

How can I hide the query-string parameters in the URL when sending an email to user with link and be able in the same time to read grab them when page is loaded in the browser?
Using: NodeJs, Angular1, MongoDb.
Code:
exports.newPass = function (req, res) {
User.findOne({
email: req.body.email
}, function (err, email) {
console.log('Email: ' + email);
if (err) throw err;
if (!email) {
console.log('Email: ' + email);
return res.json({ message: 'This Email does not exist!' });
}
var transport = mailer.createTransport({
host:'localhost',
port: 25,
secure: false,
auth: {
user: "userName",
pass: "passWord"
}
});
var mail = {
from: "DevOps <dev#localhost>",
to: "dev#localhost",
subject: "Set New Password",
text: "To set new Password: ",
html: '<strong>To set new Password: </strong>'
+ ' <a href="http://localhost:4000/endPoint#!/signup?m='
+ email.email
+ '&fn='
+ email.fullName
+ '&_id='
+ email._id
+ '">Restore Password</a>'
}
transport.sendMail(mail, function(error, response){
if(error){
console.log( 'Server Error: ' + error );
}else{
console.log( 'Message sent: ' + JSON.stringify(response.messageId) );
}
transport.close();
});
return res.json({ Ok: 'New Password will be send to you... please check your Emails' });
});
};
I'm able to manage this in the Angular Controller by adding the following:
$location.search({});
but the parameters and the values are still visible in the email-link.
They disappear after the user clicks on the email-link and goes to browser.
I would like to hide them also in the email which being sent to the recipient.
If safety is not a concern, you could create an object with the data you need, stringify it and then encode it in base 64. You can easily decode this back to the JSON string.
You'd do something like this in Node:
var data = { email: email.email, fn: email.fullName, _id: email._id };
data = JSON.stringify(data);
data = Buffer.from(data).toString('base64');
var mail = {
from: "DevOps <dev#localhost>",
to: "dev#localhost",
subject: "Set New Password",
text: "To set new Password: ",
html: '<strong>To set new Password: </strong>'
+ ' Restore Password'
}
Note that anyone can decode this back.
Depending on where you want to get this data back, you'd have to check different ways on how to decode this data. It's pretty similar in Node:
Buffer.from(b64string, 'base64');
However, if you don't want people to be able to decode this, then you'd have to take a different approach.
What I would do is generate a random hash, and store it in the database somewhere, indicating that it's connected to some user that wants a password change. You can then send that hash to the user, and look it up when the URL you sent is requested.

Categories