Setup:
New MVC5 Project with just Web API. Added Facebook AppId and Secret.
I can get Token for my Web API from Token endpoint by passing in UserName and Password. Then use that token for further calls.
BUT I want to register new users with the help of Facebook SDK in iOS app. I am using Facebook SDK to get Access Token. (Assume at this point, I have an Access Token).
Next thing I know is to call api/Account/RegisterExternal endpoint by passing this token in Authorization header with Bearer [Access Token] but this result in 500 server error.
I guess I know the reason, Cookie is missing. I made the same call with a cookie from Fidler and it worked. (Cookie is received by going to URL provided by ExternalLogins endpoint).
As cookie is missing await Authentication.GetExternalLoginInfoAsync(); inside the RegisterExternal action returns null.
// POST api/Account/RegisterExternal
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("RegisterExternal")]
public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var info = await Authentication.GetExternalLoginInfoAsync();
if (info == null)
{
return InternalServerError();
}
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
IdentityResult result = await UserManager.CreateAsync(user);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
result = await UserManager.AddLoginAsync(user.Id, info.Login);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
I don't want to make 3 calls to my Web API to ask for external logins and then goto that URL and authenticate in a Web Browser for Facebook access token and then call the RegisterExternal endpoint with that access token and Cookie that I need to collect between these calls.
As I said I didn't change anything in template except the Facebook Ids. Still the code is as below.
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
app.UseFacebookAuthentication(
appId: "xxxxxxxxxxxxxxx",
appSecret: "xxxxxxxxxxxxxxxxxxxxxxxx");
}
}
as far as I know, Web API doesn't need Cookie and that appears true when I have Local Token from Token endpoint but why does it require Cookie in the first place when doing ExternalRegister
WebApiConfig class looks like this and shouldn't config.SuppressDefaultHostAuthentication(); avoid any Cookie needs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
I don't know if I am missing the point here.. My intentions are to not need to use web browser in a native iOS app for the token. That is Facebook SDK to get access token and using that call RegisterExternal to get the Local Token and create that users Identity.
I did my homework and I am stuck on this thought. Thoughts appreciated!