I'm using Google/Facebook/LinkedIn authentication on my ASP.NET MVC 5 website. For some reason, every once in a while, some users complain about not being able to login because they get redirect_uri_mismatch error.
As I said, what's strange is that the error seems to happen intermittently and only to some users. I'm including my code down below so that you can point out what I'm doing wrong.
Here's the Startup.cs file code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Web;
using Owin;
using Owin.Security.Providers.LinkedIn;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.Facebook;
using Microsoft.Owin.Security.Google;
namespace myWebSite
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// Set up app to use cookies for authentication
var cookieOptions = new CookieAuthenticationOptions
{
AuthenticationType = "Cookies",
CookieSecure = CookieSecureOption.SameAsRequest,
ExpireTimeSpan = TimeSpan.FromMinutes(60),
SlidingExpiration = true,
LoginPath = new Microsoft.Owin.PathString("/Account/Login")
};
app.UseCookieAuthentication(cookieOptions);
// Set up external authentication
var externalCookieOptions = new CookieAuthenticationOptions
{
AuthenticationType = "ExternalCookie",
CookieSecure = CookieSecureOption.SameAsRequest,
ExpireTimeSpan = TimeSpan.FromMinutes(10),
AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Passive,
CookieManager = new Helpers.SystemWebCookieManager()
};
app.UseCookieAuthentication(externalCookieOptions);
#region Facebook Authentication
var fbOptions = new FacebookAuthenticationOptions
{
AuthenticationType = "Facebook",
AppId = "myFacebookAppIdGoesHere",
AppSecret = "myFacebookAppSecretGoesHere",
SignInAsAuthenticationType = "ExternalCookie",
Provider = new FacebookAuthenticationProvider
{
OnAuthenticated = async ctx =>
{
var token = ctx.AccessToken;
var id = ctx.Id;
var firstName = ctx.User["first_name"];
var middleName = ctx.User["middle_name"];
var lastName = ctx.User["last_name"];
var gender = ctx.User["gender"];
var birthday = ctx.User["birthday"];
var email = ctx.User["email"];
var username = ctx.User["username"];
ctx.Identity.AddClaim(new Claim("urn:myWebSite:AuthorityId", "1", ClaimValueTypes.String, "Facebook"));
if (id != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, id.ToString(), ClaimValueTypes.String, "Facebook"));
}
if (firstName != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.GivenName, firstName.ToString(), ClaimValueTypes.String, "Facebook"));
}
if (middleName != null)
{
ctx.Identity.AddClaim(new Claim("urn:facebook:middle_name", middleName.ToString(), ClaimValueTypes.String, "Facebook"));
}
if (lastName != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.Surname, lastName.ToString(), ClaimValueTypes.String, "Facebook"));
}
if (gender != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.Gender, gender.ToString(), ClaimValueTypes.String, "Facebook"));
}
if (birthday != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.DateOfBirth, birthday.ToString(), ClaimValueTypes.String, "Facebook"));
}
if (email != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.Email, email.ToString(), ClaimValueTypes.String, "Facebook"));
}
ctx.Identity.AddClaim(new Claim("fb.token", token));
},
OnReturnEndpoint = async ctx =>
{
if (ctx.Identity == null)
{
// User is not authenticated
throw new HttpException(403, "Unable to authenticate with Facebook...");
}
else
{
if (ctx.Properties.Dictionary.ContainsKey("returnUrl"))
{
ctx.RedirectUri += "?returnUrl=" + ctx.Properties.Dictionary["returnUrl"];
}
}
}
}
};
fbOptions.Scope.Add("user_birthday");
fbOptions.Scope.Add("email");
app.UseFacebookAuthentication(fbOptions);
#endregion
#region Google Authentication
var googleOptions = new GoogleOAuth2AuthenticationOptions
{
AuthenticationType = "Google",
ClientId = "myGoogleClientIdGoesHere",
ClientSecret = "myGoogleClientSecretGoesHere",
SignInAsAuthenticationType = "ExternalCookie",
Provider = new GoogleOAuth2AuthenticationProvider
{
OnAuthenticated = async ctx =>
{
var token = ctx.AccessToken;
var id = ctx.Id;
var firstName = ctx.GivenName;
var middleName = ctx.User["middle_name"];
var lastName = ctx.FamilyName;
var gender = ctx.User["gender"];
var birthday = ctx.User["birthday"];
var email = ctx.Email;
var username = ctx.User["username"];
ctx.Identity.AddClaim(new Claim("urn:myWebSite:AuthorityId", "3", ClaimValueTypes.String, "Google"));
if (id != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, id.ToString(), ClaimValueTypes.String, "Google"));
}
if (firstName != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.GivenName, firstName.ToString(), ClaimValueTypes.String, "Google"));
}
if (middleName != null)
{
ctx.Identity.AddClaim(new Claim("urn:google:middle_name", middleName.ToString(), ClaimValueTypes.String, "Google"));
}
if (lastName != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.Surname, lastName.ToString(), ClaimValueTypes.String, "Google"));
}
if (gender != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.Gender, gender.ToString(), ClaimValueTypes.String, "Google"));
}
if (birthday != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.DateOfBirth, birthday.ToString(), ClaimValueTypes.String, "Google"));
}
if (email != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.Email, email.ToString(), ClaimValueTypes.String, "Google"));
}
ctx.Identity.AddClaim(new Claim("google.token", token));
},
OnReturnEndpoint = async ctx =>
{
if (ctx.Identity == null)
{
// User is not authenticated
throw new HttpException(403, "Unable to authenticate with Google...");
}
else
{
if (ctx.Properties.Dictionary.ContainsKey("returnUrl"))
{
ctx.RedirectUri += "?returnUrl=" + ctx.Properties.Dictionary["returnUrl"];
}
}
}
}
};
googleOptions.Scope.Add("openid");
googleOptions.Scope.Add("email");
googleOptions.Scope.Add("profile");
app.UseGoogleAuthentication(googleOptions);
#endregion
#region LinkedIn Authentication
var linkedInOptions = new LinkedInAuthenticationOptions
{
AuthenticationType = "LinkedIn",
ClientId = "myLinkedInClientIdGoesHere",
ClientSecret = "myLinkedInClientSecretGoesHere",
SignInAsAuthenticationType = "ExternalCookie",
Provider = new LinkedInAuthenticationProvider
{
OnAuthenticated = async ctx =>
{
var token = ctx.AccessToken;
var id = ctx.Id;
var firstName = ctx.User["first_name"];
var middleName = ctx.User["middle_name"];
var lastName = ctx.User["last_name"];
var gender = ctx.User["gender"];
var birthday = ctx.User["birthday"];
var email = ctx.Email;
var username = ctx.User["username"];
ctx.Identity.AddClaim(new Claim("urn:myWebSite:AuthorityId", "4", ClaimValueTypes.String, "LinkedIn"));
if (id != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, id.ToString(), ClaimValueTypes.String, "LinkedIn"));
}
if (firstName != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.GivenName, firstName.ToString(), ClaimValueTypes.String, "LinkedIn"));
}
if (middleName != null)
{
ctx.Identity.AddClaim(new Claim("urn:linkedin:middle_name", middleName.ToString(), ClaimValueTypes.String, "LinkedIn"));
}
if (lastName != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.Surname, lastName.ToString(), ClaimValueTypes.String, "LinkedIn"));
}
if (gender != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.Gender, gender.ToString(), ClaimValueTypes.String, "LinkedIn"));
}
if (birthday != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.DateOfBirth, birthday.ToString(), ClaimValueTypes.String, "LinkedIn"));
}
if (email != null)
{
ctx.Identity.AddClaim(new Claim(ClaimTypes.Email, email.ToString(), ClaimValueTypes.String, "LinkedIn"));
}
ctx.Identity.AddClaim(new Claim("linkedin.token", token));
},
OnReturnEndpoint = async ctx =>
{
if (ctx.Identity == null)
{
// User is not authenticated
throw new HttpException(403, "Unable to authenticate with LinkedIn...");
}
else
{
if (ctx.Properties.Dictionary.ContainsKey("returnUrl"))
{
ctx.RedirectUri += "?returnUrl=" + ctx.Properties.Dictionary["returnUrl"];
}
}
}
}
};
app.UseLinkedInAuthentication(linkedInOptions);
#endregion
}
}
}
In my settings for Google, Facebook and LinkedIn, I only had http://www.yourdomain.com/signin-{socialsite} as the redirect uri. When I also added http://yourdomain.com/signin-{socialsite}, it fixed the issue. If you're having this issue, please make sure you have the return uri with AND without the "www".