TL;DR: if you’ve already set up your Twitter application to allow requesting of users emails and don’t feel like learning the intricacies of building OAuth authorization headers from scratch in C#, check out this blog post which shows you a very simple way to retrieve a user’s email using LinqToTwitter.
This blog post assumes you are already familiar with setting up these providers for your site. If not, check out these links:
- Authenticating a user with LinkedIn in ASP.NET Core
- Enabling authentication using external providers
I’ve been working on implementing external login providers for the Humanitarian Toolbox‘s AllReady open source project on GitHub. So far, ASP.NET Core has made it very easy to choose which external authentication providers I want to use using existing OWIN middleware provided by the framework.
So far I’ve implemented external logins for Facebook, Microsoft and Google using claims provided by the OWIN middleware. After authenticating with the external login provider, the code redirects the user to our signup form to fill out any other information we require to register with AllReady that the external login provider did not supply. Here is an example using Google.
However, when I implemented the Twitter external login provider, I received nothing back in the form of claims that I could use on our signup form, not even email address:
Intrigued, I started to dig into why there is nothing (especially email address) being provided by the Twitter external login provider
Twitter, Where’s the Love?
It is not well known that Twitter does not provider a user’s email address when using ASP.NET Core’s ExternalLoginInfo claims collection. There are complaints online about this policy, but it appears that Twitter is sticking to its guns as far as not giving out their user’s email address for those authenticating with OAuth.
It seems that every other external provider easily allows us to get at this information. It’s as easy as looking at the ExternalLoginInfo.ExternalPrincipal’s list of claims and referencing this claim:
All other providers give me a value when this claim is accessed, Twitter does not.
Why Twitter does not provide this information is beyond me. It seems as if the email address used to sign up for a Twitter account needs to be unique:
so I’m not too sure what is driving Twitter’s choice to not give this information out.
Either way, after a lot of reading, researching and coding, it IS possible to get an externally authenticated Twitter user’s email address through the magic of Twitter “special permissions” and LinqToSql.
But first, a little background on creating a Twitter application and configuring it to allow retrieval of a user’s email.
How To Set Up Your Twitter Application
If you haven’t already set up a Twitter application, you can start by going to go to: https://apps.twitter.com/. Click on “Create New App”.
This will bring you to the “Create an application” page:
You can put anything you want into the Name and Description field. Assuming you are developing locally (aka, “localhost”), you need to provide the localhost address (and port number assuming you’re using IIS Express) for both the Website and Callback URL fields.
Note: Twitter will not take “localhost” as a legit URL format, you need to change “localhost” to “127.0.01” in order to register your Website and Callback URL.
When you’re ready, hit “Create your Twitter Application”. You’ll be brought to this page:
Now that you have created your new Twitter application, if you tried to use .NET’s external login provider to retrieve the user’s email, it won’t be provided. As a matter of fact, if you look at the rest of the tabs on your newly added application, you won’t see any place to allow access to a user’s email address.
We need to fill out a form on Twitter’s website.
Tell Twitter You Want Access to Special Permissions (Twitter employs genies)
Go to https://support.twitter.com/forms/platform. You’ll see this page:
Choose “I need access to special permissions” and fill in your Application Name and Application ID for you newly created Twitter application, but most importantly, fill in “Email address” in the Permissions Requested field. Hit Submit and you should get a verification email:
now wait for up to a couple days for someone at Twitter to get back to you (I’m not making this up, you actually have to wait for someone to review your request).
__ day(s) later, a genie at Twitter sends you an email saying “your wish is my command” (aka, you were given special permissions you asked for)
But we’re not done yet. Twitter has only given us the ability to request email permissions through our application. We still need to go and enable it. Head back to your application. On the Permissions tab you should see this newly added section:
Check the checkbox and click Update Settings. You will now be able to request a user’s email address.
But how do we send a request for this additional information?
ExternalLoginInfo, Where Is My Email Address?
Even after all the Twitter setup we’ve done, when going to authenticate through SignInManager.GetExternalLoginInfoAsync the System.Security.Claims.ClaimTypes.Email is still returning nothing!
So, although we’ve told Twitter we want to be able to access a user’s email, and enabled it for our application, we’re still not able to get at that information.
To get the user’s email address, we’ll need to make another http request once the external user has been authenticated. Twitter provides information about how to do that here:
Further down on this page, you’ll see that it’s possible to generate an OAuth signature using your newly added application:
Pick your application from the drop down and you’ll be brought to this page:
with everything pre-filled except for the Request query field. You need to type “include_email=true” into this field in order for the correct signature to be generated that will include the user’s email address in the response.
After populating the Request query field, click on “Get OAuth Signature”, and you will see something very similar to this at the bottom of the page:
Seeing the cURL command listed there (which is a downloadable HTTP client available from:https://curl.haxx.se/), you can drop to PowerShell and execute HTTP request via curl:
It’s great that Twitter “gives” us the correct code to invoke this request using an HttpClient like cURL, but how are we supposed to generate these values and put together the authorization header in C#?
Twitter OAuth HTTP Header Hell
Building your own OAuth http authorization header and query string sounds easy enough, but after looking at the instructions for how to do this via Twitter docs:
And reading through these implementation efforts:
There are a LOT of rules to follow. Things like:
- oauth_timestamp is “the number of seconds since the Unix epoch at the point the request is generated”
- HMACSHA1 hasher requires the combination of the “oauth_consumer_secret” and “oauth_token_secret” in order to generate the value for the “oauth_signature”
- oauth_signature parameter contains a value which is generated by running all of the other request parameters and two secret values through a signing algorithm
- oh, by the way, did we mention the order of the parameters matters as well?
All of this seemed like a LOT of work and a LOT of code to write. I kept Googling trying out different search criteria to see if there was any other way to do this besides dropping down to “the metal” and building the OAuth authorization header by scratch in C#.
Luckily, I found a blog post that showed me how to do it using LinqToTwitter.
LinqToTwitter to the Rescue
I found this blog post:
http://www.bigbrainintelligence.com/Post/get-users-email-address-from-twitter-oauth-ap and cried with joy.
- the sample code provided was very straight-forward
- it did not require building an OAuth authorization header
- it was geared towards asp.net core and working with an ExternalLoginCallback action method, which is pretty much how we had things set up on our end
- it used LINQ (and who doesn’t love LINQ)
Another useful blog post showed me how to authorize with Twitter using LinqToTwitter’s SingelUserAuthorizer, and once authorized, how to query for the user’s email address.
After installing the LinqToTwitter nuget package and implementing the code from the blog post, I easily retrieved the user’s email address, and as a bonus, also found I could retrieve their name as well!
FINALLY, AllReady’s registration form for an authenticated Twitter user looked like this:
instead of all form fields being blank.
Things were looking really bleak there for a bit 😉
It’s not that I’m against drilling down to the metal to learn how OAuth authorization headers work, but there is a such a plethora of libraries available to abstract that type of work away, it was worth the extra research to find something that solved my problem in a simple way, rather than me reinventing the wheel for the 100th time.
Now I can say that AllReady is … ehm… “all ready” to successfully pull user information into its registration form from all of our implemented external login providers.