I'm implementing a reset password feature for users of my site. Once a verified, well-defined user signs up, a unique token is generated (specifically for this case), saved in the database, and included as a parameter in the querystring of the link included in the "Forgot password" email to the user. The user then checks their email, clicks on the link, and will be redirected to a view where they can redefine their password.
The main obstruction I am dealing with in this process is obtaining the unique token as a parameter from the link when the user clicks on that link in their email. I referenced the official Express documentation and specified the route (which is activated in the email when the user clicks on it in their inbox to go to a view to reset their password), and wrote the following route to handle it:
usersRouter.route('/reset/passwordLoggedOut/:token')
.get(emails.resetPasswordForgot);
with the ensuing resetPasswordForgot() function (minified for your viewing convenience):
function resetPasswordForgot(req, res){
const token = req.params.token;
console.log(token);
res.send(200);
}
Console.log(token) is currently showing up null when I expect it to contain the user password token.
Some more background information, I'm using SendGrid for all of my automated emails, Mailinator for testing the emails as the user, and here is what the route looks like when I hover over the link within the email. (I realize that the image is small and probably impossible to view without zooming in several times, but I wanted to include as much of the URL as possible)
Please let me know what I need to do to get the token param from the link in the email.
You need access by the query attribute:
function resetPasswordForgot(req, res){
const token = req.query.token;
console.log(token);
res.send(200);
}
Related
I am trying to create a react, NodeJS application for a movie review webpage where the user log in using email. His/her profile info would then link to this email address. However, I would like to change the extraction of the profile information. Instead of linking to this email address, which the user could change, to a particular userid instead (which is unique) and would not be modified.
Retreive user by its Email
for example :
var mail= "user#email.com"
service.get('/users/' + mail).then(response => {
console.log(response.data);
});
Hi, We have created a bot where user interact with the bot. so our
bot has two type of queries static and dynamic queries. if user asks
static query we don't ask for SIGN IN but if user ask for dynamic
query than we ask user to SIGN IN and redirect to SIGN IN page than
we ask mobile no and dob and send OTP to user and than verify the
user and send back a token in response which we get in further
request. The problem is let use suppose user came on our our bot and
asked static query so i store the chat of user to my db initially I
create a userId for user like this conv.user.storage.userId =
'unique_id' and store this unique_id in my db to identify the user
next time and send back. Next time same bot get same userId and keep
updating my chat in db for this userId. Now the problem comes when
users asks a dynamic query than I have to redirect user to our
account linking page. user is redirectd to account linking page and
user fill his mobile no. and DOb and we send a otp to usermobile.
When our SendOtp api is called I create a userId and store in
databse but I want the userId which I set before for static queries
(conv.user.storeage.userId) this one. How can I get this Id. Can we
pass this userId as params to when to ask for SIGN In (conv.ask(new
SignIn('To get your account details'))) and get this static query
userId in my SendOtp API. I need same ID to send further to update
chat.
When you create a SignIn request, you cannot provide any additional data in that request. However, you are able to provide this behavior when your Action gets a callback. You will get a Sign In event that can be set to when the user signs in. At that point you can add your additional logic to connect the user's account on your backend with the account ID in userStorage.
Here's an example of what it may look like.
app.handle('linkAccount', async conv => {
let payload = conv.headers.authorization;
if (payload) {
// Perform account merge
await performAccountMerge(payload.email, conv.user.storage.userId)
}
});
async function performAccountMerge(authorizedEmail, savedUserId) {
await saveInDatabaseForEmail(authorizedEmail, savedUserId)
}
I am working on some client side web app like a chrome extension that needs access to outlook mail and calendar. I followed the instruction on https://dev.outlook.com/RestGettingStarted and successfully got access and refresh tokens to retrieve data.
However, I cannot find any way of implementing "logout". The basic idea is to let user sign out and login with a different outlook account. In order to do that, I removed cached tokens, requested access tokens in interactive mode. The login window did pop out, but it took any valid email address, didn't let me input password and finally returned tokens for previous account. So I was not able to really use a different account until the old token expired.
Can anyone please tell me if it is possible to send a request to revoke the tokens so people can use a different account? Thanks!
=========================================================
Update:
Actually it is the fault of chrome.identity api. I used chrome.identity.LaunchWebAuthFlow to init the auth flow. It caches user's identity but no way to remove it. So we cannot really "logout" if using this api.
I used two logouts via launchWebAuthFlow - first I called the logout link to my app, then secondly, I called the logout link to Google.
var options = {
'interactive': false,
'url': 'https://localhost:44344/Account/Logout'
}
chrome.identity.launchWebAuthFlow(options, function(redirectUri) {});
options = {
'interactive': false,
'url': 'https://accounts.google.com/logout'
}
chrome.identity.launchWebAuthFlow(options, function(redirectUri) {});
Here's my workflow:
Ember action on new user signup is to send Express the user data.
Express then creates a web token, encrypts the contents, and puts a link in an email that it sends with Nodemailer.
The email is sent successfully.
User goes to their email and clicks on the link.
On clicking the link, Express gets the token from the query params decrypts and decodes the token, and creates a New User.
All of the above works ok, but here is where I'm stuck. I'd like for the user to be redirected back to the Ember frontend, and automatically logged in. This is the bit I'm stuck on. Here is the Server code:
<!-- language: lang-js -->
signUpUser.save().then(function(model) {
res.set('location', 'http://localhost:4200/login');
res.status(302).json({user:model})
});
I'm able to successfully redirect back but I'm not able to capture the json data in my ember code, and I'm not sure where or how in Ember I can call a login action in the given scenario.
I have a feeling my approach may be wrong? Because email verification is a common thing. Also, I'd rather not have to make users input their form information more than once.
Here's how I'm doing this:
In Express, add query params to the response url after saving user:
signUpUser.save().then(function(model) {
res.set('location', 'http://localhost:4200/login?token=' + token + 'id=' + id);
res.status(302).json({user:model})
});
In Ember, in the /login route beforeModel hook, grab the query params:
beforeModel: function(transition) {
console.log(transition.queryParams.token);
if (transition.queryParams.token) {
this.controllerFor('login').send('assignTokenToUser', transition.queryParams.token, transition.queryParams.id);
};
if (!Ember.isEmpty(this.controllerFor('login').get('token'))) {
return this.transitionTo('courses');
}
}
I'm not sure this is the Ember Way, but the key here is being able to grab queryParams of the transition object.
Can you provide some more information about the authentication system you are using? It sounds like you are using a JWT to convey some information about email verification, but how do you authenticate API requests? Do you use another JWT that is stored in a cookie? If so you want to create this cookie when they arrive with their verification JWT.
Disclaimer: I work at Stormpath and we have a fully-featured email verification workflow in our service. While we don’t have an integration for Ember.js, we do have a good overview of JWTs and Single Page Applications, it may be useful at a high level: Token Based Authentication for Single Page Apps
We do have an Angular integration, if you have the option to switch frameworks: Stormpath AngularJS SDK
I'm trying to do a simple contact form in a node app, using nodemailer. I want all the msg to be sent from a gmail account I made for this purpose, to my personnal mail.
on the client side, all I do is to get the name/mail/message of the customer and send it to the server. It works fine locally but fails to work when deployed (on heroku btw).
After a quick search, it seems I have to generate a ClientId and ClientSecret from Google Developers Console - which I did - but when it comes to generating a "refresh token" iI'm completely lost.
var smtpTransport = nodemailer.createTransport("SMTP",{
service:"Gmail",
auth:{
XOAuth2: {
user:"myaccount#gmail.com",
clientId:"",
clientSecret:"",
refreshToken:""
}
}
});
I am confused : What exactly is a refresh token and how do I get one ?
Notes by this answer original's author:
So, I finally managed to figure it out. I'm surprised I couldn't find more ressources about that so for those who need to use Gmail with Nodemailer
I found the answer here: http://masashi-k.blogspot.fr/2013/06/sending-mail-with-gmail-using-xoauth2.html
Try creating a new User if you already had one and things ain't working fine. It was the case for me.
I hope this will be useful to someone,
Cheers
Question 1: What exactly is a refresh token?
From documentation found here:
A refresh token provides your app continuous access to Google APIs while the user is not logged into your application.
(...)
Considerations:
Be sure to store the refresh token safely and permanently, because you can only obtain a refresh token the first time that you perform the code exchange flow.
There are limits on the number of refresh token that are issued—one limit per client/user combination, and another per user across all clients. If your application requests too many refresh tokens, it may run into these limits, in which case older refresh tokens stop working.
See also Offline Access and Using a refresh token.
Question 2: How do I get one?
Step 1: Obtain OAuth 2.0 credentials at Google Developers Console
As stated here, you should:
Go to the Google Developers Console.
Select a project, or create a new one.
In the sidebar on the left, expand APIs & auth. Next, click APIs. Select the Enabled APIs link in the API section to see a list of all your enabled APIs. Make sure that the "Gmail API" is on the list of enabled APIs. If you have not enabled it, select the Gmail API from the list of APIs (under Google Apps APIs), then select the Enable API button for the API.
In the sidebar on the left, select Credentials.
If you haven't done so already, create your project's OAuth 2.0 credentials by clicking Create new Client ID, and providing the information needed to create the credentials.
Look for the Client ID and Client secret in the table associated with each of your credentials.
PAY SPECIAL ATTENTION TO specifying https://developers.google.com/oauthplayground
as a Redirect URI when you create a new User in the console.
Otherwise, you will have an error.
Step 2: Obtain the refresh token at Google OAuth2.0 Playground
Go to the Google Oauth2.0 Playground.
Click the Gear Button on the right-top. Set your Client ID and Client Secret obtained from the Google Developers Console, and select Access token location as Authorization header w/ Bearer prefix. Close this configuration overlay.
Set up the scopes. Use https://mail.google.com/ as it's the one need by nodemailer. Then click the Authorize APIs button.
After OAuth2.0 authorization, exchange authorization code for tokens and voilá! your refresh token is ready-to-use
For those who have been looking around for a working example/code snippet, follow Radioreve's Answer until you are able to get the access token and refresh token. (Basically, go to the playground, make sure it asks for access for sending mail and mail.google.com, give permission, exchange authorization code for tokens)
Note that the expires time I entered was new Date().getTime() + 2000 which was close to the expiration seconds seen on the playground. I am not sure if I had to enter access token and expiration time accurately as it seems to be refreshing the token automatically.
Use this sample code written in ECMAScript 6:
const user_name = 'something#gmail.com';
const refresh_token = '';
const access_token = '';
const client_id = '';
const client_secret = '';
const email_to = 'receiver#gmail.com';
const nodemailer = require('nodemailer');
let transporter = nodemailer
.createTransport({
service: 'Gmail',
auth: {
type: 'OAuth2',
clientId: client_id,
clientSecret: client_secret
}
});
transporter.on('token', token => {
console.log('A new access token was generated');
console.log('User: %s', token.user);
console.log('Access Token: %s', token.accessToken);
console.log('Expires: %s', new Date(token.expires));
});
// setup e-mail data with unicode symbols
let mailOptions = {
from : user_name, // sender address
to : email_to, // list of receivers
subject : 'Hello ✔', // Subject line
text : 'Hello world ?', // plaintext body
html : '<b>Hello world ?</b>', // html body
auth : {
user : user_name,
refreshToken : refresh_token,
accessToken : access_token,
expires : 1494388182480
}
};
// send mail with defined transport object
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
return console.log(error);
}
console.log('Message sent: ' + info.response);
});
You can Simple use Google SMTP to send email. Use nodemailer with smtp.google.com and email and App password (not gmail password).
How to Get App Password.
Now you have to enable 2 Step Verification in Google (How to Enable 2 Step Auth)
You need to generate App Specific Password. Goto Google My Account > Security
Click on App Password > Select Other and you will get App Password
You can use normal smtp with email and App password.