Can't validate email token when calling Accounts.sendVerificationEmail a second time - meteor

I installed a process of email address verification using Meteor Accounts. It works fine, but when Accounts.sendVerificationEmail() is called a second time, the Account.verifyEmail() method always refuse with a 403: Verify email link expired when called on the new token.
The email verification token set in Meteor.users by the first call to Accounts.sendVerificationEmail() is not changed when calling that method again: It's still the link sent with the first email that will work.
I can't find any info related to this in the Meteor documentation or on the internet. Is there something to do before beeing able to call Accounts.sendVerificationEmail() a second time (like cleanup or something?).

I had the same issue implementing the resend link to my website. I got around this by removing all the previous verficationTokens.
Here are two methods of applying a fix to this problem:
This is the preferred method if you already have an active database with n amount of users having trouble verifying their accounts. Place this code in a separate Meteor.call() method after you call the Accounts.sendVerificationEmail() method:
Meteor.users.update({_id: Meteor.userId()}, {'$push': services.email.verificationTokens": {$each: [], $slice: -1}}});
This will empty all the other tokens except for the last token created by the latest call to Accounts.sendVerificationEmail() method.
This method may be quicker for implementing newer projects or when implementing meteor-accounts in a new project. Similar to step 1) place this code in a new Meteor.call() method and call it after calling Accounts.sendVerificationEmail() method:
Meteor.users.update({_id: Meteor.userId()}, {'$pop': {"services.email.verificationTokens": -1}});
This will pop the first entry of the verificationTokens and thus the only entry is left with the latest token generated in Accounts.sendVerificationEmail() method.
Hope this helps.

When you use sendVerificationEmail(), a new entry appears in users collection : 'services.email.verificationTokens' and you'll see in 'emails.[x].verified' is false.
When you use verifyEmail(), the 'emails.[x].verified' go to true, and values in 'services.email.verificationTokens' disappear. So, if you try to use a second time verifyEmail(), it can't because email still verified and verification token is delete.
If you send a second time sendVerificationEmail() with a new token, the new link allows you to use verifyEmail() without error message.

Related

Can't reset user's password in Google Identity Toolkit: "CAPTCHA_CHECK_FAILED"

I'm trying to setup my Google Identity Toolkit so users can reset their passwords. I'm following the documentation here: https://developers.google.com/identity/toolkit/web/required-endpoints#send_email_url
I'm using the PHP Gitkit Client outlined here: https://github.com/google/identity-toolkit-php-client/blob/master/src/GitkitClient.php
Specifically the function getOobResults() on line 307 seems to be unhappy for some reason. Here's where I'm at:
User sets up account and logs in successfully
User then logs out and starts to log back in, enters email in and clicks "Forgot password"
reCaptcha is shown, click check box and then hit continue
At this point my 'Send Email URL' endpoint (gitkitEmail.php) is successfully called and the following POST is set to it (dropping the full '&response' param since it goes on for a while):
action=resetPassword&email=xodfebefa%40nada.ltd&challenge&response=03ACgFB9tGlNt2KAGhrVY....
I then take that string and parse it using parse_str(); since getOobResults() is looking for an array. However, response I get back is always:
{
"response_body": {
"error": "CAPTCHA_CHECK_FAILED"
}
}
I searched around but can't find any details on this error. Any help would be appreciated. I don't have a reCaptcha setup anywhere on my site, unsure if this is expecting me to do that and that's why it's failing? Also, I did bump all my code to a production environment and got the same error there as I did on my localhost.

meteor-shopify authenticator getPermanentAccessToken with code

I'm using the froatsnook:shopify atmosphere package to create an embedded public app on Shopify. I currently have a couple issues:
1) Getting the access token from the "code" query parameter after a user authenticates. As it mentions in the docs here, I'm supposed to use authenticator.getPermanentAccessToken(code) but what I don't understand is how to get call authenticator if the "code" parameter appears on the callback route (at that point, the authenticator I instantiated on the client pre-auth route is out of scope).
2) The "oAuth" function callback is never called for some reason, even when assigning it to Shopify.onAuth on the server.
3) The difference between post_auth_uri and redirect_uri ?
// I call this during 'onBeforeAction' for iron-router
function beforeAuth (query) {
// is this necessary..?
console.assert(Meteor.isClient);
// get shop name like 'myshop' from 'myshop.shopify.com';
const shop = query.shop.substring(0, query.shop.indexOf('.'));
// use api_key stored in settings
var api_key = Meteor.settings.public.shopify.api_key;
// Prepare to authenticate
var authenticator = new Shopify.PublicAppOAuthAuthenticator({
shop: shop,
api_key: api_key,
keyset: 'default',
embedded_app_sdk: true,
redirect_uri: 'https://45a04f23.ngrok.com/testContent',
//post_auth_uri: ???
// This is doesn't seem to be getting
// called after clicking through the OAuth dialog
onAuth: function(access_token) {
ShopifyCredentials.insert({
shop: shop,
api_key: api_key,
access_token: access_token
});
}
});
// Should i use something different with iron-router?
location.href = authenticator.auth_uri;
// how do i get code in this scope???
// authenticator.getPermanentAccessToken(code);
}
There are a few issues with the way you are trying to set up the authenticator, although it's not really your fault because the way Scenario 3 works in the docs is not an 'out of the box' solution and requires a bunch of custom code, including your own handler (I can provide a gist if you REALLY want to build your own handler, but I suggest using the new server-side onAuth callback instead)
1. Specifying a redirect_uri overrides the package's default redirect_uri handler which is Meteor.absoluteUrl("/__shopify-auth").
So instead, completely remove redirect_uri and put your testContent url in post_auth_uri instead.
2. ShopifyCredentials does not exist in this package. If you want to use it that way, make sure you actually have defined a collection called 'ShopifyCredentials' and insert the record from the server, not the client. Note that you will still need to add a keyset on the server for the API methods to work. If you are using user accounts and would like to permanently store credentials, I suggest saving the credentials to the database and adding the keyset via a server-side onAuth callback.
3. authenticator.getPermanentAccessToken(code) isn't useful unless you are using your own handler. Instead, you can just get access_token from the onAuth callback.
Also keep in mind that if you ever need to reauthenticate from inside the embedded app, you need to use window.top.location.href to break out of the iframe.
If you want a complete, working boilerplate example with user accounts see my gist here:
Authentication with Accounts and Persistent Keysets
If you aren't using accounts, you can use this gist instead, but please note that you really need to come up with some way to check that the current client has permission to request the keyset for a given shop before going to production:
Authentication with Persistent Keysets

Getting Access Token Data From OAuth Template of Asp.net

I'm trying to get access token of facebook client when a user logged in with asp.net's oauth template. But I couldn't acquire the access token when i tried some methods that i found on internet like;
AuthenticationResult result = OpenAuth.VerifyAuthentication("RegisterExternalLogin.aspx");
string actok = result.ExtraData["accesstoken"];
This try wasn't successfull. How can i acquire the access token?
I see noone has replied to your question even though it has been 10 days so I'll take a stab at it.
You mentioned that you are using asp.net's OAuth template. So I think you are looking at the line
AuthenticationResult result = OpenAuth.VerifyAuthentication("RegisterExternalLogin.aspx");
in the ExternalLoginCallback() action in AccountController.cs
As far as I can tell your syntax is correct. In fact also tested it out myself and it works. I guess you can try another way of accessing the same property
String myaccesstoken_value1 = result.ExtraData.Values.ToArray()[5];
That will give you the same result as result.ExtraData["accesstoken"]
If that does not work either then I would imagine that there is some problem with the authentication itself, rather than with your syntax here. I'm assuming you have VS2012 Express, so use the debugger to see what values are present in your variable 'result'. If it is empty, then it would indicate why you second statement errors out, and it would also indicate that there is a problem in the code before you get to this point.
Also keep in mind during testing that when you log into your app using OAuth providers such as Facebook, even when you log out of the website you continue to remain logged into facebook. You actually have to go to facebook.com and click logout there also (unless you write some additional code in your asp.net app to do a remote logout). I don't know if this applies to your situation, just giving you a heads up.
Please vote if this helps.

Behat step definition sometimes executed, sometimes not

I have the following scenario's:
#wip
Scenario: Attempt to get account information of an activator without credentials
Given an activator with e-mail "dietervds#email.com" and password "testpassword" already exists
When I send a GET request to "/activators/1"
Then the response code should be 401
#wip
Scenario: Attempt to get account information of another activator then myself
Given an activator with e-mail "dietervds#email.com" and password "testpassword" already exists
And an activator with e-mail "eviltwin#email.com" and password "testpassword" already exists
And I am authenticating as "eviltwin#email.com" with "testpassword" password
When I send a GET request to "/activators/1"
Then the response code should be 401
The database is dropped and re-created from schema before every scenario.
The step 'given an activator with ...' inserts a new user into the database.
However! It doesn't always do that for both users.
This is the step implementation:
/**
* #Given /^an activator with e-mail "([^"]*)" and password "([^"]*)" already exists$/
*/
public function anActivatorWithEMailAndPasswordAlreadyExists($email, $password)
{
$activatorManager = $this->getContainer()->get('am.manager.activator');
#$logger = $this->getContainer()->get('logger');
#$logger->debug("Email: $email, password: $password");
$activator = $activatorManager->createActivator($email, $password);
$activatorManager->save($activator);
}
Now the weird thing:
In that last step, I should be getting two inserts: one for dietervds, one of eviltwin.
I get the two inserts when I:
Run only one scenario
Output something in logging (creating the 'logger' doesn't help, I need to output something. What I output doesn't have to be dynamic, it can just be a fixed string)
I only get one insert (for dietervds) when I:
Run the two scenarios together
Or when I don't output any logging in the step implementation
I am completely baffled by this.
Is there something obvious that's missing? Might it be some sort of caching problem in the step definitions? (the logging might change the signature or something, not sure)
Any feedback is welcome :-)
Cheers!
Dieter
Does this step def do an ajax call?
When I send a GET request to "/activators/1"
if it does you could try adding some wait time in there to give your dom time to load the result
Whens to Thens work best when you are submitting forms with press or following links or doing go to's to redirect the browser which initiates a full request response cycle that triggers the robot to wait for a new dom to load.
With ajax that doesn't happen exactly the same way.
If you aren't doing ajax I recommend you just use the built in step defs of
When I follow "/activators/1" instead
There is a way to prevent caching in your yaml config. Here is an example config we use for chrome but it should work the same for any browser driver
default:
extensions:
Behat\MinkExtension\Extension:
base_url: https://yurwebsite.com
goutte: ~
browser_name: "googlechrome"
selenium2:
capabilities: { "browser": "googlechrome", "version": "23", "applicationCacheEnabled": false }
The last boolean param does the trick for our browser caching issues

Get refresh token google api

I can't get my refresh token with my code. I can only get my access token, token type etc.,
I have followed some tutorials like putting access_type=offline on my login URL:
echo "<a href='https://accounts.google.com/o/oauth2/auth?"
. "access_type=offline&client_id=123345555.apps.googleusercontent.com& "
. "scope=https://www.googleapis.com/auth/calendar+https://www.googleapis.com/auth/plus.me&response_type=code& "
. "redirect_uri=http://www.sample.com/sample.php&state=/profile'>Google</a>";
and my fields in getting the access token:
$fields=array(
'code'=> urlencode($authcode),
'client_id'=> urlencode($clientid),
'client_secret'=> urlencode($clientsecret),
'redirect_uri'=> urlencode($redirecturi),
'grant_type'=> 'authorization_code',
);
but I can't get refresh_token, just the access_token, token_type, id_token and expires_in.
Found out by adding this to your url parameters
approval_prompt=force
Update:
Use access_type=offline&prompt=consent instead.
approval_prompt=force no longer works
https://github.com/googleapis/oauth2client/issues/453
If I may expand on user987361's answer:
From the offline access portion of the OAuth2.0 docs:
When your application receives a refresh token, it is
important to store that refresh token for future use. If your
application loses the refresh token, it will have to re-prompt the
user for consent before obtaining another refresh token. If you need
to re-prompt the user for consent, include the approval_prompt
parameter in the authorization code request, and set the value to
force.
So, when you have already granted access, subsequent requests for a grant_type of authorization_code will not return the refresh_token, even if access_type was set to offline in the query string of the consent page.
As stated in the quote above, in order to obtain a new refresh_token after already receiving one, you will need to send your user back through the prompt, which you can do by setting approval_prompt to force.
Cheers,
PS This change was announced in a blog post as well.
It is access_type=offline that you want.
This will return the refresh token the first time the user authorises the app. Subsequent calls do not force you to re-approve the app (approval_prompt=force).
See further detail:
https://developers.google.com/accounts/docs/OAuth2WebServer#offline
This is complete code in PHP using google official SDK
$client = new Google_Client();
## some need parameter
$client->setApplicationName('your application name');
$client->setClientId('****************');
$client->setClientSecret('************');
$client->setRedirectUri('http://your.website.tld/complete/url2redirect');
$client->setScopes('https://www.googleapis.com/auth/userinfo.email');
## these two lines is important to get refresh token from google api
$client->setAccessType('offline');
$client->setApprovalPrompt('force'); # this line is important when you revoke permission from your app, it will prompt google approval dialogue box forcefully to user to grant offline access
For our app we had to use both these parameters access_type=offline&prompt=consent.
approval_prompt=force did not work for us
Hi I followed following steps and I had been able to get the refresh token.
Authorization flow has two steps.
Is to obtain the authorization code using https://accounts.google.com/o/oauth2/auth? URL.
For that a post request is sent providing following parameters. 'scope=' + SCOPE + '&client_id=' + CLIENTID + '&redirect_uri=' + REDIRECT + '&response_type=' + TYPE + '&access_type=offline' Providing above will receive a authorization code.
Retrieving AcessToken and RefreshToken using https://accounts.google.com/o/oauth2/token? URL.
For that a post request is sent providing following parameters.
"code" : code,
"client_id" : CID,
"client_secret" : CSECRET,
"redirect_uri" : REDIRECT,
"grant_type" : "authorization_code",
So in your first attempt once you authorize the permissions you will be able to get the Refresh token. Subsequent attempts will not provide the refresh token. If you want the token again the revoke the access in you application.
Hope this will help someone cheers :)
OAuth has two scenarios in real mode.
The normal and default style of access is called online.
In some cases, your application may need to access a Google API when the user is not present,It's offline scenarios .
a refresh token is obtained in offline scenarios during the first authorization code exchange.
So you can get refersh_token is some scenarios ,not all.
you can have the content in https://developers.google.com/identity/protocols/OAuth2WebServer#offline
.
Since March 2016, use prompt=consent to regenerate Google API refresh token.
As mentioned in https://github.com/googleapis/oauth2client/issues/453,
approval_prompt=force has been replaced with prompt=none|consent|select_account
For those using the Google API Client Library for PHP and seeking offline access and refresh tokens beware as of the time of this writing the docs are showing incorrect examples.
currently it's showing:
$client = new Google_Client();
$client->setAuthConfig('client_secret.json');
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');
// offline access will give you both an access and refresh token so that
// your app can refresh the access token without user interaction.
$client->setAccessType('offline');
// Using "consent" ensures that your application always receives a refresh token.
// If you are not using offline access, you can omit this.
$client->setApprovalPrompt("consent");
$client->setIncludeGrantedScopes(true); // incremental auth
source: https://developers.google.com/identity/protocols/OAuth2WebServer#offline
All of this works great - except ONE piece
$client->setApprovalPrompt("consent");
After a bit of reasoning I changed this line to the following and EVERYTHING WORKED
$client->setPrompt("consent");
It makes sense since using the HTTP requests it was changed from approval_prompt=force to prompt=consent. So changing the setter method from setApprovalPrompt to setPrompt follows natural convention - BUT IT'S NOT IN THE DOCS!!! That I found at least.

Resources