I'm creating a MVC Core app and deploying it to an Azure App Service. I'm trying to send emails using SendGrid from the application which seems to be working fine in my local environment but does not work in production. I'm using free subscriptions for anything Azure.
I've followed this pretty much to the tee.
This type of question has popped up on stack overflow and github (here and here, etc), but after going through about 50 such posts nothing seems to be working for me. Reading through the documentation in SendGrid doesn't help a lot either because all the examples provided looks like my own code. I don't get any exceptions, and like I mentioned it works just fine locally.
Please help
Code
string sendGridApiKey = _configuration["SENDGRID_API_KEY"];
var client = new SendGridClient(sendGridApiKey);
var msg = new SendGridMessage();
msg.SetFrom(new EmailAddress(email: "management#enr.com",
name: "ENR Management"));
msg.AddTo(new EmailAddress(email: user.Email, name: user.FriendlyName));
msg.SetSubject("Reset Password");
msg.AddContent(MimeType.Html, $"Please reset your password by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'> clicking here </a>.");
msg.AddContent(MimeType.Text, "Please reset your password by clicking the link");
var response = await client.SendEmailAsync(msg).ConfigureAwait(false);
Being called by
_emailService.SendResetPasswordEmail(
user: user,
callbackUrl: callbackUrl).Wait();
appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "XXX",
"ENRModelsDB": "XXX"
},
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"SENDGRID_API_KEY": "SG.XXX",
"AllowedHosts": "*"
}
I also have the same key/value in my App Service in Azure under Configuration -> Application setting for what it's worth.
Could it be that your App Service has the configuration setup with different value?
Another suggestion to you is you to debug your app running in the App Service to see what exactly is happening.
Introduction to Remote Debugging on Azure Web Sites
*it is old but it will give you the idea.
I finally found the issue and I feel so stupid.
I only send 1 email from my app, the password reset email. On my live environment, it would fail at this step in ForgotPassword.cshtml.cs (the scaffolded page)
if (user == null || !(await _userManager.IsEmailConfirmedAsync(user)))
{
// Don't reveal that the user does not exist or is not confirmed
return RedirectToPage("./ForgotPasswordConfirmation");
}
because when I seeded the user I did not set email confirmed to be true.
Could not have done it without the remote debug suggestion. It never even got to the part where it is supposed to send the email, and no errors reports because there was none.
Found some newer articles (here and here) to help with the remote debugging which came with its own rabbit holes.
Thanx for the suggestion #KodiaMx
I'm in the midst of testing mod_http_api to replace the existing usage of mod_rest in our implementation.
I can unrestrict access to some commands from group of IP addresses by using option "admin_ip_access". I can successfully execute some commands (e.g. change_password).
However, for some cases, we may require login as well for both user (own)and admin(own and other user).
However, when I tried to login with Basic Auth. It's not successful. I'm keep on getting the following. If my assumption is correct, this might be related to configuration.
Will be much appreciated if someone could show me how the correct configuration should be done.
{
"status": "error",
"code": 31,
"message": "Command need to be run with admin priviledge."
}
Current config
modules:
mod_http_api:
admin_ip_access: admin_ip_access_rule
acl:
admin_ip_acl:
ip:
- "xx.xx.xx.xx/32"
access:
admin_ip_access_rule:
admin_ip_acl:
- all
EDIT
For testing purpose, I've enabled the following configuration:
commands_admin_access: configure
commands:
- add_commands:
- status
- get_roster
- change_password
- register
- unregister
- registered_users
- muc_online_rooms
- oauth_issue_token
I able to run both of user and admin commands successfully for those listed commands inside add_commands tags. It works as expected. However, I still facing some issues, most related to the IP restriction. Calling the API from the host that is not listed in admin_ip_acl also successful where I expect to get error when calling for non-whitelited host
The API requires an OAuth token for authentication. You need to generate one with correct scope. When a command is restricted to an admin, you need to also pass the HTTP header: "X-Admin: true" to let ejabberd know that it should consider you would like to act as an admin.
I have an Ember CLI app with a Rails back-end API. I am trying to set up end-to-end testing by configuring the Ember app test suite to send requests to a copy of the Rails API. My tests are working, but I am getting the following strange error frequently:
{}
Expected: true
Result: false
at http://localhost:7357/assets/test-support.js:4519:13
at exports.default._emberTestingAdaptersAdapter.default.extend.exception (http://localhost:7357/assets/vendor.js:52144:7)
at onerrorDefault (http://localhost:7357/assets/vendor.js:42846:24)
at Object.exports.default.trigger (http://localhost:7357/assets/vendor.js:67064:11)
at Promise._onerror (http://localhost:7357/assets/vendor.js:68030:22)
at publishRejection (http://localhost:7357/assets/vendor.js:66337:15)
This seems to occur whenever a request is made to the server. An example test script which would recreate this is below. This is a simple test which checks that if a user clicks a 'login' button without entering any email/password information they are not logged in. The test passes, but additionally I get the above error before the test passes. I think this is something to do with connecting to the Rails server, but have no idea how to investigate or fix it - I'd be very grateful for any help.
Many thanks.
import Ember from 'ember';
import { module, test } from 'qunit';
import startApp from 'mercury-ember/tests/helpers/start-app';
module('Acceptance | login test', {
beforeEach: function() {
this.application = startApp();
},
afterEach: function() {
Ember.run(this.application, 'destroy');
}
});
test('Initial Login Test', function(assert)
{
visit('/');
andThen(function()
{
// Leaving identification and password fields blank
click(".btn.login-submit");
andThen(function()
{
equal(currentSession().get('user_email'), null, "User fails to login when identification and password fields left blank");
});
});
});
You can check in the Network panel of Chrome or Firefox developer tools that the request is being made. At least with ember-qunit you can do this by getting ember-cli to run the tests within the browser rather than with Phantom.js/command-line.
That would help you figure out if it's hitting the Rails server at all (the URL could be incorrect or using the wrong port number?)
You may also want to see if there is code that needs to be torn down. Remember that in a test environment the same browser instance is used so all objects need to be torn down; timeouts/intervals need to be stopped; events need to be unbound, etc.
We had that issue a few times where in production there is no error with a utility that sent AJAX requests every 30 seconds, but in testing it was a problem because it bound itself to the window (outside of the iframe) so it kept making requests even after the tests were torn down.
I'd like to share a CloudKit asset in the public database with people who aren't using my app. From the CKAsset class, there's only a fileURL property, which points to a local file, so no URL given.
On the documentation for CloudKit Web Services, however, there is a "referencing existing assets" request, which in its' response gives a downloadURL to the asset file.
Calling this from my app gives me a 421 status code, which is described in documentation as "AUTHENTICATION_REQUIRED", as it requires a ckSession parameter to be given, which is a "session identifier of an authenticated user". It also passes a redirectURL, where a user can type in their iCloud login, and then be re-directed back to the web application, now with a session identifier.
Opening this URL inside the app didn't immediately return the session identifier, but instead expected the user to go through the login process in a browser, before receiving their session ID.
This seems totally off-track, and the wrong thing to be doing. I'm certainly not going to make my users log in to iCloud through a web interface. The only thing missing for that CloudKit Web Services url is the session ID. Is there a way for me to get that using the CloudKit framework? Or is there another way for me to find out this file's URL?
If you are using Apple's official CloudKit.js, here is the code to configure your CloudKit access:
window.addEventListener('cloudkitloaded', function() {
console.log('Cloudkit loaded');
CloudKit.configure({
locale: 'en-us',
containers: [{
containerIdentifier: 'iCloud.com.getYoursInXcode',
apiTokenAuth: {
apiToken: 'getThisInCloudkitDashboardApiAccess',
persist: true //Set cookie
},
environment: 'production'
}]
});
// Do your thing here
})
If you are fetching records in your backend, it is still better to get your API token instead of using the Server-To-Server process.
For example, query records in GO, to fetch a record, compose your request body like this
sampleRequest = []byte('{
"resultsLimit":"4",
"desiredKeys": ["recordTitle","recordDescription"],
"query": {
"recordType": "myRecord",
"sortBy": {
"fieldName": "rank",
"ascending": true
}
}
}')
And send it to the following Url
http.NewRequest("POST", ""https://api.apple-cloudkit.com/database/1/iCloud.com.yourIdentifier/production/public/records/query?ckAPIToken=YOURTOKEN", bytes.NewBuffer(RequestBody))
Is anyone else having a difficult time getting Twitters oAuth's callback URL to hit their localhost development environment.
Apparently it has been disabled recently. http://code.google.com/p/twitter-api/issues/detail?id=534#c1
Does anyone have a workaround. I don't really want to stop my development
Alternative 1.
Set up your .hosts (Windows) or etc/hosts file to point a live domain to your localhost IP. such as:
127.0.0.1 xyz.example
where xyz.example is your real domain.
Alternative 2.
Also, the article gives the tip to alternatively use a URL shortener service. Shorten your local URL and provide the result as callback.
Alternative 3.
Furthermore, it seems that it works to provide for example http://127.0.0.1:8080 as callback to Twitter, instead of http://localhost:8080.
I just had to do this last week. Apparently localhost doesn't work but 127.0.0.1 does Go figure.
This of course assumes that you are registering two apps with Twitter, one for your live www.mysite.example and another for 127.0.0.1.
Just put http://127.0.0.1:xxxx/ as the callback URL, where xxxx is the port for your framework
Yes, it was disabled because of the recent security issue that was found in OAuth. The only solution for now is to create two OAuth applications - one for production and one for development. In the development application you set your localhost callback URL instead of the live one.
Callback URL edited
http://localhost:8585/logintwitter.aspx
Convert to
http://127.0.0.1:8585/logintwitter.aspx
This is how i did it:
Registered Callback URL:
http://127.0.0.1/Callback.aspx
OAuthTokenResponse authorizationTokens =
OAuthUtility.GetRequestToken(ConfigSettings.getConsumerKey(),
ConfigSettings.getConsumerSecret(),
"http://127.0.0.1:1066/Twitter/Callback.aspx");
ConfigSettings:
public static class ConfigSettings
{
public static String getConsumerKey()
{
return System.Configuration.ConfigurationManager.AppSettings["ConsumerKey"].ToString();
}
public static String getConsumerSecret()
{
return System.Configuration.ConfigurationManager.AppSettings["ConsumerSecret"].ToString();
}
}
Web.config:
<appSettings>
<add key="ConsumerKey" value="xxxxxxxxxxxxxxxxxxxx"/>
<add key="ConsumerSecret" value="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"/>
</appSettings>
Make sure you set the property 'use dynamic ports' of you project to 'false' and enter a static port number instead. (I used 1066).
I hope this helps!
Use http://smackaho.st
What it does is a simple DNS association to 127.0.0.1 which allows you to bypass the filters on localhost or 127.0.0.1 :
smackaho.st. 28800 IN A 127.0.0.1
So if you click on the link, it will display you what you have on your local webserver (and if you don't have one, you'll get a 404). You can of course set it to any page/port you want :
http://smackaho.st:54878/twitter/callback
I was working with Twitter callback url on my localhost. If you are not sure how to create a virtual host ( this is important ) use Ampps. He is really cool and easy. In a few steps you have your own virtual host and then every url will work on it. For example:
download and install ampps
Add new domain. ( here you can set for example twitter.local) that means your virtual host will be http://twitter.local and it will work after step 3.
I am working on Win so go under to your host file -> C:\Windows\System32\Drivers\etc\hosts and add line: 127.0.0.1 twitter.local
Restart your Ampps and you can use your callback. You can specify any url, even if you are using some framework MVC or you have htaccess url rewrite.
Hope This Help!
Cheers.
Seems nowadays http://127.0.0.1 also stopped working.
A simple solution is to use http://localtest.me instead of http://localhost it is always pointing to 127.0.0.1 And you can even add any arbitrary subdomain to it, and it will still point to 127.0.0.1
See Website
When I develop locally, I always set up a locally hosted dev name that reflects the project I'm working on. I set this up in xampp through xampp\apache\conf\extra\httpd-vhosts.conf and then also in \Windows\System32\drivers\etc\hosts.
So if I am setting up a local dev site for example.com, I would set it up as example.dev in those two files.
Short Answer: Once this is set up properly, you can simply treat this url (http://example.dev) as if it were live (rather than local) as you set up your Twitter Application.
A similar answer was given here: https://dev.twitter.com/discussions/5749
Direct Quote (emphasis added):
You can provide any valid URL with a domain name we recognize on the
application details page. OAuth 1.0a requires you to send a
oauth_callback value on the request token step of the flow and we'll
accept a dynamic locahost-based callback on that step.
This worked like a charm for me. Hope this helps.
It can be done very conveniently with Fiddler:
Open menu Tools > HOSTS...
Insert a line like 127.0.0.1 your-production-domain.com, make sure that "Enable remapping of requests..." is checked. Don't forget to press Save.
If access to your real production server is needed, simply exit Fiddler or disable remapping.
Starting Fiddler again will turn on remapping (if it is checked).
A pleasant bonus is that you can specify a custom port, like this:
127.0.0.1:3000 your-production-domain.com (it would be impossible to achieve this via the hosts file). Also, instead of IP you can use any domain name (e.g., localhost).
This way, it is possible (but not necessary) to register your Twitter app only once (provided that you don't mind using the same keys for local development and production).
edit this function on TwitterAPIExchange.php at line #180
public function performRequest($return = true)
{
if (!is_bool($return))
{
throw new Exception('performRequest parameter must be true or false');
}
$header = array($this->buildAuthorizationHeader($this->oauth), 'Expect:');
$getfield = $this->getGetfield();
$postfields = $this->getPostfields();
$options = array(
CURLOPT_HTTPHEADER => $header,
CURLOPT_HEADER => false,
CURLOPT_URL => $this->url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false
);
if (!is_null($postfields))
{
$options[CURLOPT_POSTFIELDS] = $postfields;
}
else
{
if ($getfield !== '')
{
$options[CURLOPT_URL] .= $getfield;
}
}
$feed = curl_init();
curl_setopt_array($feed, $options);
$json = curl_exec($feed);
curl_close($feed);
if ($return) { return $json; }
}
I had the same challenge and I was not able to give localhost as a valid callback URL. So I created a simple domain to help us developers out:
https://tolocalhost.com
It will redirect any path to your localhost domain and port you need. Hope it can be of use to other developers.
set callbackurl in twitter app : 127.0.0.1:3000
and set WEBrick to bind on 127.0.0.1 instead of 0.0.0.0
command : rails s -b 127.0.0.1
Looks like Twitter now allows localhost alongside whatever you have in the Callback URL settings, so long as there is a value there.
I struggled with this and followed a dozen solutions, in the end all I had to do to work with any ssl apis on local host was:
Go download: cacert.pem file
In php.ini * un-comment and change:
curl.cainfo = "c:/wamp/bin/php/php5.5.12/cacert.pem"
You can find where your php.ini file is on your machine by running php --ini in your CLI
I placed my cacert.pem in the same directory as php.ini for ease.
These are the steps that worked for me to get Facebook working with a local application on my laptop:
goto apps.twitter.com
enter the name, app description and your site URL
Note: for localhost:8000, use 127.0.0.1:8000 since the former will not work
enter the callback URL matching your callback URL defined in TWITTER_REDIRECT_URI your application
Note: eg: http://127.0.0.1/login/twitter/callback (localhost will not work).
Important enter both the "privacy policy" and "terms of use" URLs if you wish to request the user's email address
check the agree to terms checkbox
click [Create Your Twitter Application]
switch to the [Keys and Access Tokens] tab at the top
copy the "Consumer Key (API Key)" and "Consumer Secret (API Secret)" to TWITTER_KEY and TWITTER_SECRET in your application
click the "Permissions" tab and set appropriately to "read only", "read and write" or "read, write and direct message" (use the least intrusive option needed for your application, for just and OAuth login "read only" is sufficient
Under "Additional Permissions" check the "request email addresses from users" checkbox if you wish for the user's email address to be returned to the OAuth login data (in most cases check yes)