Response for preflight is invalid (redirect) using Asp.Net Web API - asp.net-web-api

I'm developing a website which uses AngularJS in the frontend and ASP.NET web API in the backend. I'm trying to configure external logins(Facebook) for my site. I have already enabled Cors on the API. The order of API calls are:
API call to
api/Account/ExternalLogins?returnUrl=%2F&generateState=true
to get a list of external login providers.
This returns
[{"name":"Facebook",
"url":"/api/Account/ExternalLogin?provider=Facebook&response_type=token&client_id=self&redirect_uri=http%3A%2F%2Flocalhost%3A15359%2F&state=xxxxxxxxxx",
"state":"xxxxxxxxxx"}]
Now I send a GET request to url returned earlier. This triggers a preflight request to https://www.facebook.com/dialog/oauth?response_type=code&client_id=xxxxxxx&redirect_uri=https%3A%2F%2Flocalhost%3A44327%2Fsignin-facebook&scope=manage_pages&state=xxxxxxx which gives error. This is never redirected to Facebook Login Page.
Both the request and response headers for /api/Account/ExternalLogin?provider=Facebook&response_type=token&client_id=self&redirect_uri=http%3A%2F%2Flocalhost%3A15359%2F&state=xxxxxxxxxx contains Access-Control-Allow-Origin:*
But for the preflight request https://www.facebook.com/dialog/oauth?response_type=code&client_id=xxxxxxx&redirect_uri=https%3A%2F%2Flocalhost%3A44327%2Fsignin-facebook&scope=manage_pages&state=xxxxxxx Access-Control-Allow-Origin header is missing.
The code snippets are mentioned below.
app.js
$httpProvider.defaults.headers.common['Access-Control-Allow-Origin'] = '*';
$httpProvider.defaults.headers.common['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, Content-Length, X-Requested-With';
$httpProvider.defaults.headers.common['Access-Control-Allow-Credentials'] = true;
$httpProvider.defaults.headers.common['Access-Control-Allow-Method'] = 'GET, PUT, POST, DELETE, OPTIONS';
Start.Auth.cs
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
app.UseCors(CorsOptions.AllowAll);
// 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
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/api/Account/ExternalLogin"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
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),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
//Provider = new AuthorizationServerProvider()
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
// Enables the application to remember the second login verification factor such as phone or email.
// Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
// This is similar to the RememberMe option when you log in.
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
var facebookOptions = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions
{
AppId = "xxxxxxxxx",
AppSecret = "xxxxxxxxx",
BackchannelHttpHandler = new FacebookBackChannelHandler(),
Provider = new FacebookAuthenticationProvider()
{
OnAuthenticated = (context) =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken));
return Task.FromResult(0);
}
},
SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie,
SendAppSecretProof = true
};
facebookOptions.Scope.Add(ConfigurationManager.AppSettings["Facebook_Scope"]);
facebookOptions.AuthenticationMode = AuthenticationMode.Passive;
app.UseFacebookAuthentication(facebookOptions);
AccountController
[Authorize]
[EnableCors(origins: "*", headers: "*", methods: "*")]
[RoutePrefix("api/Account")]
public class AccountController : ApiController
{
private const string LocalLoginProvider = "Local";
private ApplicationUserManager _userManager;
public AccountController()
{
}
public AccountController(ApplicationUserManager userManager,
ISecureDataFormat<AuthenticationTicket> accessTokenFormat)
{
UserManager = userManager;
AccessTokenFormat = accessTokenFormat;
}
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
public ISecureDataFormat<AuthenticationTicket> AccessTokenFormat { get; private set; }
// GET api/Account/UserInfo
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("UserInfo")]
public UserInfoViewModel GetUserInfo()
{
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
return new UserInfoViewModel
{
Email = User.Identity.GetUserName(),
HasRegistered = externalLogin == null,
LoginProvider = externalLogin != null ? externalLogin.LoginProvider : null
};
}
// POST api/Account/Logout
[Route("Logout")]
[AllowAnonymous]
public IHttpActionResult Logout()
{
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
return Ok();
}
// POST api/Account/AddExternalLogin
[Route("AddExternalLogin")]
public async Task<IHttpActionResult> AddExternalLogin(AddExternalLoginBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
AuthenticationTicket ticket = AccessTokenFormat.Unprotect(model.ExternalAccessToken);
if (ticket == null || ticket.Identity == null || (ticket.Properties != null
&& ticket.Properties.ExpiresUtc.HasValue
&& ticket.Properties.ExpiresUtc.Value < DateTimeOffset.UtcNow))
{
return BadRequest("External login failure.");
}
ExternalLoginData externalData = ExternalLoginData.FromIdentity(ticket.Identity);
if (externalData == null)
{
return BadRequest("The external login is already associated with an account.");
}
IdentityResult result = await UserManager.AddLoginAsync(User.Identity.GetUserId(),
new UserLoginInfo(externalData.LoginProvider, externalData.ProviderKey));
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// GET api/Account/ExternalLogin
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)]
[AllowAnonymous]
[Route("ExternalLogin", Name = "ExternalLogin")]
public async Task<IHttpActionResult> GetExternalLogin(string provider, string error = null)
{
if (error != null)
{
return Redirect(Url.Content("~/") + "#error=" + Uri.EscapeDataString(error));
}
if (!User.Identity.IsAuthenticated)
{
return new ChallengeResult(provider, this);
}
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
if (externalLogin == null)
{
return InternalServerError();
}
if (externalLogin.LoginProvider != provider)
{
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
return new ChallengeResult(provider, this);
}
ApplicationUser user = await UserManager.FindAsync(new UserLoginInfo(externalLogin.LoginProvider,
externalLogin.ProviderKey));
bool hasRegistered = user != null;
if (hasRegistered)
{
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(UserManager,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookieIdentity = await user.GenerateUserIdentityAsync(UserManager,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.UserName);
Authentication.SignIn(properties, oAuthIdentity, cookieIdentity);
}
else
{
IEnumerable<Claim> claims = externalLogin.GetClaims();
ClaimsIdentity identity = new ClaimsIdentity(claims, OAuthDefaults.AuthenticationType);
Authentication.SignIn(identity);
}
return Ok();
}
// GET api/Account/ExternalLogins?returnUrl=%2F&generateState=true
[AllowAnonymous]
[Route("ExternalLogins")]
public IEnumerable<ExternalLoginViewModel> GetExternalLogins(string returnUrl, bool generateState = false)
{
IEnumerable<AuthenticationDescription> descriptions = Authentication.GetExternalAuthenticationTypes();
List<ExternalLoginViewModel> logins = new List<ExternalLoginViewModel>();
string state;
if (generateState)
{
const int strengthInBits = 256;
state = RandomOAuthStateGenerator.Generate(strengthInBits);
}
else
{
state = null;
}
foreach (AuthenticationDescription description in descriptions)
{
ExternalLoginViewModel login = new ExternalLoginViewModel
{
Name = description.Caption,
Url = Url.Route("ExternalLogin", new
{
provider = description.AuthenticationType,
response_type = "token",
client_id = Startup.PublicClientId,
redirect_uri = new Uri(Request.RequestUri, returnUrl).AbsoluteUri,
state = state
}),
State = state
};
logins.Add(login);
}
return logins;
}
// POST api/Account/Register
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// 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();
}
protected override void Dispose(bool disposing)
{
if (disposing && _userManager != null)
{
_userManager.Dispose();
_userManager = null;
}
base.Dispose(disposing);
}
}
I know this is achievable using MVC Account Controller. I'm looking for a way to do this entirely using web api with no dependency on MVC.
Thanks!

Related

google calendar api net api The access token has expired and could not be refreshed. Errors: refresh error, refresh error, refresh error

I'm new to google api. I'm using google .net api, I'm getting the error:
The access token has expired and could not be refreshed. Errors: refresh error, refresh error, refresh error
I'm able to see the login screen, I accept the permissions request, and I got redirected to Index 2 correctly. When the calendar service is going to be used (execute) it crashes with the already mentioned error.
I already set the token as offline in the GOOGLE_AUTH_URL_TEMPLATE variable. That is supposed to be used for long term tokens.
Main Auth Class
public class TestOAuth2
{
private string applicationName = "g calendar test api";
private string clientId = "---";//From Google Developer console https://console.developers.google.com
private string clientSecret = "---";//From Google Developer console https://console.developers.google.com
private string[] scopes = new string[] {
CalendarService.Scope.Calendar, // Manage your calendars
CalendarService.Scope.CalendarReadonly // View your Calendars
};
private UserCredential userCredential;
string GOOGLE_AUTH_URL_TEMPLATE = "https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&approval_prompt=force&scope={0}&response_type=code&redirect_uri={1}&client_id={2}&login_hint=";
string clientRedirectUri= "http://localhost:57618/Home/Index2";
private CalendarService calendarService;
public TestOAuth2(string access_token)
{
ClientSecrets clientSecrets = new ClientSecrets
{
ClientId = clientId,
ClientSecret = clientSecret
};
GoogleAuthorizationCodeFlow flow = null;
TokenResponse token = new TokenResponse
{
AccessToken = access_token
};
flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = clientSecrets,
Scopes = scopes
});
userCredential = new UserCredential(flow, "user", token);
calendarService = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = userCredential,
ApplicationName = applicationName
});
}
public string GetGoogleOAuthURL()
{
return string.Format(GOOGLE_AUTH_URL_TEMPLATE, String.Join("+", scopes), clientRedirectUri, clientId);
}
private void InitializeCalendarService()
{
calendarService = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = userCredential,
ApplicationName = applicationName
});
}
public string GetEvents()
{
try
{
if (calendarService == null)
{
InitializeCalendarService();
}
var eventRequest = calendarService.Events.List("primary");
eventRequest.TimeMin = DateTime.Now;
eventRequest.ShowDeleted = false;
eventRequest.SingleEvents = true;
eventRequest.MaxResults = 10;
eventRequest.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime;
var events = eventRequest.Execute();
string sEvents = "";
foreach (var evt in events.Items)
{
sEvents += evt.Description + "\n<br>";
}
return sEvents;
}
catch (Exception ex)
{
return ex.Message;
}
}
}
Home Controller
public class HomeController : Controller
{
private TestOAuth2 Google;
public string GetGoogleOauthUrl()
{
string temp = "";
try
{
Google = new TestOAuth2(string.Empty);
temp = Google.GetGoogleOAuthURL();
}
catch (Exception ex)
{
temp = ex.Message;
}
return temp;
}
public string GetEvents()
{
string access_token = Request.Headers.Get("access_token");
string temp = "";
try
{
Google = new TestOAuth2(access_token);
temp = Google.GetEvents();
}
catch (Exception ex)
{
temp = ex.Message;
}
return temp;
}
public ActionResult Index()
{
return View();
}
public ActionResult Index2()
{
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
Index View
<html>
<body>
<script>
document.addEventListener('DOMContentLoaded', function (event) {
fetch("http://localhost:57618/Home/GetGoogleOauthUrl", {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
})
.then(response => {
if (response.ok) {
response.text().then(myAnswer => {
console.log(myAnswer);
window.open(myAnswer, '_blank');
})
} else {
console.error.log("HTTP-Error: " + response.status);
}
});
});
</script>
Hello! Wait For A New Window!
</body>
</html>
Index 2 View
<html>
<body>
<script>
function getUrlParameter(name) {
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
var results = regex.exec(location.search);
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
};
document.addEventListener('DOMContentLoaded', function (event) {
let token = getUrlParameter("code");
fetch("http://localhost:57618/Home/GetEvents", {
method: 'GET',
headers: {
'Content-Type': 'application/json',
"access_token": token
}
})
.then(response => {
if (response.ok) {
response.text().then(myAnswer => {
console.log(myAnswer);
document.write("<br><br><br>");
document.write(myAnswer);
})
} else {
console.error.log("HTTP-Error: " + response.status);
}
});
});
</script>
</body>
</html>
What you want to use is a special token that does not need to be refreshed I believe.
To do that you need to create a project inside GCP and then create a Service Account and Download a json key inside the new Service Account created.
Enable the Calendar API inside the new created project and copy the email of the service account. Go to the calendar you want to give access to your api and add the email you copy from the service account. Now you can use the service account json key to authenticate and it wont have expiration.

Set HTTPOnly cookie from the ASP.net Web Api

I am trying to implement jwt token authentication in my web api. I have a front end app which is in angular 8. i want to save the token in cookie.how can i achieve this?? what will be the syntax for the subsequent call from the angular,if i save the token in cookie after login.
TokenValidationHandler
internal class TokenValidationHandler : DelegatingHandler
{
private static bool TryRetrieveToken(HttpRequestMessage request, out string token)
{
token = null;
IEnumerable<string> authzHeaders;
if (!request.Headers.TryGetValues("Authorization", out authzHeaders) || authzHeaders.Count() > 1)
{
return false;
}
var bearerToken = authzHeaders.ElementAt(0);
token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
return true;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpStatusCode statusCode;
string token;
//determine whether a jwt exists or not
if (!TryRetrieveToken(request, out token))
{
statusCode = HttpStatusCode.Unauthorized;
//allow requests with no token - whether a action method needs an authentication can be set with the claimsauthorization attribute
return base.SendAsync(request, cancellationToken);
}
try
{
const string sec = "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1";
var now = DateTime.UtcNow;
var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(sec));
SecurityToken securityToken;
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
TokenValidationParameters validationParameters = new TokenValidationParameters()
{
ValidAudience = "http://localhost:50191",
ValidIssuer = "http://localhost:50191",
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
LifetimeValidator = this.LifetimeValidator,
IssuerSigningKey = securityKey
};
//extract and assign the user of the jwt
Thread.CurrentPrincipal = handler.ValidateToken(token, validationParameters, out securityToken);
HttpContext.Current.User = handler.ValidateToken(token, validationParameters, out securityToken);
return base.SendAsync(request, cancellationToken);
}
catch (SecurityTokenValidationException e)
{
statusCode = HttpStatusCode.Unauthorized;
}
catch (Exception ex)
{
statusCode = HttpStatusCode.InternalServerError;
}
return Task<HttpResponseMessage>.Factory.StartNew(() => new HttpResponseMessage(statusCode){ });
}
public bool LifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
{
if (expires != null)
{
if (DateTime.UtcNow < expires) return true;
}
return false;
}
}
LoginController(will generate the token)
public class LoginController : ApiController
{
[HttpPost]
public IHttpActionResult Authenticate([FromBody] LoginRequest login)
{
var loginResponse = new LoginResponse { };
LoginRequest loginrequest = new LoginRequest { };
loginrequest.Username = login.Username.ToLower();
loginrequest.Password = login.Password;
IHttpActionResult response;
HttpResponseMessage responseMsg = new HttpResponseMessage();
bool isUsernamePasswordValid = false;
if(login != null)
isUsernamePasswordValid=loginrequest.Password=="pass" ? true:false;
// if credentials are valid
if (isUsernamePasswordValid)
{
string token = createToken(loginrequest.Username);
//return the token
return Ok<string>(token);
}
else
{
// if credentials are not valid send unauthorized status code in response
loginResponse.responseMsg.StatusCode = HttpStatusCode.Unauthorized;
response = ResponseMessage(loginResponse.responseMsg);
return response;
}
}
private string createToken(string username)
{
//Set issued at date
DateTime issuedAt = DateTime.UtcNow;
//set the time when it expires
DateTime expires = DateTime.UtcNow.AddSeconds(30);
//http://stackoverflow.com/questions/18223868/how-to-encrypt-jwt-security-token
var tokenHandler = new JwtSecurityTokenHandler();
//create a identity and add claims to the user which we want to log in
ClaimsIdentity claimsIdentity = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, username)
});
const string sec = "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1";
var now = DateTime.UtcNow;
var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(sec));
var signingCredentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(securityKey,Microsoft.IdentityModel.Tokens.SecurityAlgorithms.HmacSha256Signature);
//create the jwt
var token =
(JwtSecurityToken)
tokenHandler.CreateJwtSecurityToken(issuer:"http://localhost:50191",audience:"http://localhost:50191",
subject: claimsIdentity, notBefore: issuedAt, expires: expires, signingCredentials: signingCredentials);
var tokenString = tokenHandler.WriteToken(token);
return tokenString;
}
}
Firstly, the httponly cookie cannot be accessed from JavaScript.
Secondly, please refer to the code below to return the cookie along with the response.
private HttpResponseMessage setTokenCookie(LoginResponse response)
{
var responseMessage = Request.CreateResponse(HttpStatusCode.OK, response);
var cookie = new CookieHeaderValue("token", response.Token)
{
Expires = DateTimeOffset.Now.AddDays(7),
HttpOnly = true
};
responseMessage.Headers.AddCookies(new CookieHeaderValue[] { cookie });
return responseMessage;
}
You can use the function mentioned above in your controller action method as shown below to return the cookie.
var responseWithCookie = setTokenCookie(response);
return ResponseMessage(responseWithCookie);
I've assumed that LoginResponse class has Token property.

OwinOAuthProviders RefreshToken flow

I'm building a OwinOAuth (Oauth2) provider for my company to contribute here-https://github.com/TerribleDev/OwinOAuthProviders
The challenge I'm facing is that my company generates the refresh token too along with access token and provides the expiry time for both access token and refresh token. Access token expiry is set to 1hr and using Refresh token I can refresh access tokens again and again for 100 days.
Any implementations that I have seen create a RefreshTokenProvider which I don't need as my company already sends me that. The question I have here is this-
In the AuthenticationHandler class, since tokens are in memory and not saved anywhere and Oauth tokens are always generated by default, I'm not sure where the call/logic to get access tokens based on Refresh Tokens should be done.
Do I need to create a persistent store for all returned tokens and expiry and then match expiry to make a call to RefreshTokenHandler(grant_type=refresh_token) instead of AuthenticationHandler(grant_type=authorization_code) based on that?
I'm really confused here and any help with the implementation is appreciated.
EDIT-1
I have replaced my provider's name with Hidden everywhere.
Adding code for the HiddenAuthenticationHandler.
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.Owin.Infrastructure;
using Microsoft.Owin.Logging;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Infrastructure;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Owin.Security.Providers.Hidden.Provider;
using System.Net.Http.Headers;
using System.Net;
using System.Linq;
using Microsoft.Owin.Security.OAuth;
namespace Owin.Security.Providers.Hidden
{
public class HiddenAuthenticationHandler : AuthenticationHandler<HiddenAuthenticationOptions>
{
private const string XmlSchemaString = "http://www.w3.org/2001/XMLSchema#string";
private const string AuthorizationEndPoint = "https://appcenter.Hidden.com/connect/oauth2";
private const string TokenEndpoint = "https://oauth.platform.Hidden.com/oauth2/v1/tokens/bearer";
private const string UserInfoEndpoint = "https://sandbox-accounts.platform.Hidden.com/v1/openid_connect/userinfo";//"https://accounts.Hidden.com/v1/openid_connect/userinfo";//Nimisha
private const string RevokeEndpoint = "https://developer.api.Hidden.com/v2/oauth2/tokens/revoke";//Nimisha
private const string JWKSEndpoint = "https://oauth.platform.Hidden.com/op/v1/jwks";//Nimisha
private const string IssuerEndpoint = "https://oauth.platform.Hidden.com/op/v1";//Nimisha
private const string DiscoveryEndpoint = "https://developer.Hidden.com/.well-known/openid_configuration";//Nimisha
private static string refreshToken;
private static string refreshTokenExpiresIn;
private static string tokenType;
private readonly ILogger _logger;
private readonly HttpClient _httpClient;
public HiddenAuthenticationHandler(HttpClient httpClient, ILogger logger)
{
_httpClient = httpClient;
_logger = logger;
}
//public async Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
//{
// var originalClient = context.Ticket.Properties.Dictionary["as:client_id"];
// var currentClient = context.ClientId;
// if (originalClient != currentClient)
// {
// context.SetError("invalid_clientId", "Refresh token is issued to a different clientId.");
// return Task.FromResult<object>(null);
// }
// // Change auth ticket for refresh token requests
// var newIdentity = new ClaimsIdentity(context.Ticket.Identity);
// newIdentity.AddClaim(new Claim("newClaim", "newValue"));
// var newTicket = new AuthenticationTicket(newIdentity, context.Ticket.Properties);
// context.Validated(newTicket);
// return Task.FromResult<object>(null);
//}
public async Task<AuthenticationTicket> RefreshTokenAsync()
{
AuthenticationProperties properties = null;
// OAuth2 10.12 CSRF
if (!ValidateCorrelationId(properties, _logger))
{
return new AuthenticationTicket(null, properties);
}
//var requestPrefix = Request.Scheme + "://" + Request.Host;
////var redirectUri = requestPrefix + Request.PathBase + Options.CallbackPath;
//var redirectUri = "https://be97d742.ngrok.io/signin-Hidden";
// Build up the body for the token request
var body = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "refresh_token"),
new KeyValuePair<string, string>("refresh_token", refreshToken)
};
// Request the token
var refreshTokenResponse =
await _httpClient.PostAsync(TokenEndpoint, new FormUrlEncodedContent(body));
refreshTokenResponse.EnsureSuccessStatusCode();
var text = await refreshTokenResponse.Content.ReadAsStringAsync();
// Deserializes the token response
dynamic response = JsonConvert.DeserializeObject<dynamic>(text);
var accessToken = (string)response.access_token;
var expires = (string)response.expires_in;
//string refreshToken = null;
refreshToken = (string)response.refresh_token;
refreshTokenExpiresIn = (string)response.x_refresh_token_expires_in;
tokenType = (string)response.token_type;
return new AuthenticationTicket(null, properties);
}
protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()
{
AuthenticationProperties properties = null;
try
{
string code = null;
string state = null;
var query = Request.Query;
var values = query.GetValues("code");
if (values != null && values.Count == 1)
{
code = values[0];
}
values = query.GetValues("state");
if (values != null && values.Count == 1)
{
state = values[0];
}
properties = Options.StateDataFormat.Unprotect(state);
if (properties == null)
{
return null;
}
// OAuth2 10.12 CSRF
if (!ValidateCorrelationId(properties, _logger))
{
return new AuthenticationTicket(null, properties);
}
var requestPrefix = Request.Scheme + "://" + Request.Host;
//var redirectUri = requestPrefix + Request.PathBase + Options.CallbackPath;
var redirectUri = "https://be97d742.ngrok.io/signin-Hidden";
// Build up the body for the token request
var body = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "authorization_code"),
new KeyValuePair<string, string>("code", code),
new KeyValuePair<string, string>("redirect_uri", redirectUri),
new KeyValuePair<string, string>("client_id", Options.ClientId),
new KeyValuePair<string, string>("client_secret", Options.ClientSecret)
};
// Request the token
var tokenResponse =
await _httpClient.PostAsync(TokenEndpoint, new FormUrlEncodedContent(body));
tokenResponse.EnsureSuccessStatusCode();
var text = await tokenResponse.Content.ReadAsStringAsync();
// Deserializes the token response
dynamic response = JsonConvert.DeserializeObject<dynamic>(text);
var accessToken = (string)response.access_token;
var expires = (string)response.expires_in;
//string refreshToken = null; //Nimisha
refreshToken = (string)response.refresh_token;
refreshTokenExpiresIn = (string)response.x_refresh_token_expires_in;
tokenType = (string)response.token_type;
// Get the Hidden user
var userRequest = new HttpRequestMessage(HttpMethod.Get, Options.Endpoints.UserInfoEndpoint );
userRequest.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
userRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var userResponse = await _httpClient.SendAsync(userRequest, Request.CallCancelled);
userResponse.EnsureSuccessStatusCode();
text = await userResponse.Content.ReadAsStringAsync();
var user = JObject.Parse(text);
var context = new HiddenAuthenticatedContext(Context, user, accessToken, expires, refreshToken, refreshTokenExpiresIn, tokenType)
{
Identity = new ClaimsIdentity(
Options.AuthenticationType,
ClaimsIdentity.DefaultNameClaimType,
ClaimsIdentity.DefaultRoleClaimType)
};
if (!string.IsNullOrEmpty(context.Sub))
{
context.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, context.Sub, XmlSchemaString, Options.AuthenticationType));
}
if (!string.IsNullOrEmpty(context.GivenName))
{
string Name = "";
Name = context.GivenName;
if (!string.IsNullOrEmpty(context.FamilyName))
{
Name = Name +" " + context.FamilyName;
}
context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, Name, XmlSchemaString, Options.AuthenticationType));
context.Identity.AddClaim(new Claim("urn:Hidden:name", Name, XmlSchemaString, Options.AuthenticationType));
}
if ((!string.IsNullOrEmpty(context.Email)) && (!string.IsNullOrEmpty(context.EmailVerified)))
{
if (String.Equals(context.EmailVerified, "true"))
{
context.Identity.AddClaim(new Claim(ClaimTypes.Email, context.Email, XmlSchemaString, Options.AuthenticationType));
}
}
if ((!string.IsNullOrEmpty(context.PhoneNumber)) && (!string.IsNullOrEmpty(context.PhoneNumberVerified)))
{
if (String.Equals(context.PhoneNumberVerified, "true"))
{
context.Identity.AddClaim(new Claim(ClaimTypes.MobilePhone, context.Email, XmlSchemaString, Options.AuthenticationType));
}
}
if (!string.IsNullOrEmpty(context.StreetAddress))
{
context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.StreetAddress, XmlSchemaString, Options.AuthenticationType));
}
if (!string.IsNullOrEmpty(context.Locality))
{
context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.Locality, XmlSchemaString, Options.AuthenticationType));
}
if (!string.IsNullOrEmpty(context.Region))
{
context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.Locality, XmlSchemaString, Options.AuthenticationType));
}
if (!string.IsNullOrEmpty(context.PostalCode))
{
context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.Locality, XmlSchemaString, Options.AuthenticationType));
}
if (!string.IsNullOrEmpty(context.Country))
{
context.Identity.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, context.Locality, XmlSchemaString, Options.AuthenticationType));
}
context.Properties = properties;
await Options.Provider.Authenticated(context);
return new AuthenticationTicket(context.Identity, context.Properties);
}
catch (Exception ex)
{
_logger.WriteError(ex.Message);
}
return new AuthenticationTicket(null, properties);
}
protected override Task ApplyResponseChallengeAsync()//Nimisha-1
{
if (Response.StatusCode != 401)
{
return Task.FromResult<object>(null);
}
//If Response is 401 then check here based on saved Expiration duration for token and refreshtoken and then make either Refresh Token call or Access Token call
//if(SavedTokenExpiryTime is not null and is >=DateTime.Now) then call RefreshToken api call
//or
//Call below
var challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode);
if (challenge == null) return Task.FromResult<object>(null);
var baseUri =
Request.Scheme +
Uri.SchemeDelimiter +
Request.Host +
Request.PathBase;
var currentUri =
baseUri +
Request.Path +
Request.QueryString;
//var redirectUri =
// baseUri +
// Options.CallbackPath;//Nimisha check callback path
var redirectUri = "https://be97d742.ngrok.io/signin-Hidden";
var properties = challenge.Properties;
if (string.IsNullOrEmpty(properties.RedirectUri))
{
properties.RedirectUri = currentUri;
}
// OAuth2 10.12 CSRF
GenerateCorrelationId(properties);
// comma separated
var scope = string.Join(" ", Options.Scope);
var state = Options.StateDataFormat.Protect(properties);
//Nimisha //"https://appcenter.Hidden.com/connect/oauth2" + //Nimisha check
var authorizationEndpoint =
Options.Endpoints.AuthorizationEndpoint+
"?client_id=" + Uri.EscapeDataString(Options.ClientId) +
"&response_type=code" +
"&scope=" + Uri.EscapeDataString(scope) +
"&redirect_uri=" + Uri.EscapeDataString(redirectUri) +
"&state=" + Uri.EscapeDataString(state);
Response.Redirect(authorizationEndpoint);
return Task.FromResult<object>(null);
}
public override async Task<bool> InvokeAsync()
{
return await InvokeReplyPathAsync();
}
private async Task<bool> InvokeReplyPathAsync()
{
if (!Options.CallbackPath.HasValue || Options.CallbackPath != Request.Path) return false;
// TODO: error responses
var ticket = await AuthenticateAsync();
if (ticket == null)
{
_logger.WriteWarning("Invalid return state, unable to redirect.");
Response.StatusCode = 500;
return true;
}
var context = new HiddenReturnEndpointContext(Context, ticket)
{
SignInAsAuthenticationType = Options.SignInAsAuthenticationType,
RedirectUri = ticket.Properties.RedirectUri
};
await Options.Provider.ReturnEndpoint(context);
if (context.SignInAsAuthenticationType != null &&
context.Identity != null)
{
var grantIdentity = context.Identity;
if (!string.Equals(grantIdentity.AuthenticationType, context.SignInAsAuthenticationType, StringComparison.Ordinal))
{
grantIdentity = new ClaimsIdentity(grantIdentity.Claims, context.SignInAsAuthenticationType, grantIdentity.NameClaimType, grantIdentity.RoleClaimType);
}
Context.Authentication.SignIn(context.Properties, grantIdentity);
}
if (context.IsRequestCompleted || context.RedirectUri == null) return context.IsRequestCompleted;
var redirectUri = context.RedirectUri;
if (context.Identity == null)
{
// add a redirect hint that sign-in failed in some way
redirectUri = WebUtilities.AddQueryString(redirectUri, "error", "access_denied");
}
Response.Redirect(redirectUri);
context.RequestCompleted();
return context.IsRequestCompleted;
}
}
}

get data to windows mobile app from a web API

I want to get specific data from a action in a webAPI controller to my windows mobile app .here is my webAPI action;
// GET: api/Customer/5
[ResponseType(typeof(Customer))]
public IHttpActionResult GetValidCustomer(string username,string password)
{
var customer = (from cust in db.Customers
where cust.CustomerName == username && cust.CustomerPw == password
select cust).ToList();
if (customer == null)
{
return NotFound();
}
else
{
return Ok(customer);
}
}
I have tried to consume that action as follows,but the windows emulator starts to freeze when I use that method.
public async System.Threading.Tasks.Task<bool> isValidUser(string username,string password)
{
try
{
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:2335");
var url = "api/Customer?username="+username+"&password="+password;
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
}
else
{
}
}
}
catch (Exception ex)
{
return false;
}
}

Retrieve userId and send private message with linqtotwitter

I want to send private message to Twitter with my web app in asp.net mvc3. I was doing the authorization with oauth, here is my code:
in AccountController:
public ActionResult LogOn()
{
credentials.ConsumerKey = TwitterClient.ConsumerKey;
credentials.ConsumerSecret = TwitterClient.ConsumerSecret;
auth = new MvcAuthorizer { Credentials = credentials };
auth.CompleteAuthorization(Request.Url);
if (!auth.IsAuthorized)
{
string callbackUrl = "http://127.0.0.1:31891/Account/CompleteAuth";
Uri uri = new Uri(callbackUrl);
return auth.BeginAuthorization(uri);
}
return RedirectToAction("Index", "Home");
}
After the user is authorized , he is redirect to action CompleteAuth, and I get the token and tokenSecret, here is code of this action:
public ActionResult CompleteAuth(string oauth_token, string oauth_verifier)
{
string AccessToken = oauth_token;
string AccessTokenSecret = oauth_verifier;
TempData["AccessToken"] = AccessToken;
TempData["TokenSecret"] = AccessTokenSecret;
return RedirectToAction("Tweeting","Home");
}
after, it's redirect to Home in action Tweeting, when i try to get userId and send to him direct message :
public ActionResult Tweeting()
{
var auth = new MvcAuthorizer
{
Credentials = new InMemoryCredentials()
{
ConsumerKey = TwitterClient.ConsumerKey,
ConsumerSecret = TwitterClient.ConsumerSecret,
//OAuthToken = (string)Session["AccessToken"],
//AccessToken = Session["TokenSecret"]
OAuthToken = TempData["AccessToken"] as string,
AccessToken = TempData["TokenSecret"] as string
}
};
var twitterContext = new TwitterContext(auth);
var message = twitterContext.NewDirectMessage(auth.UserId, "Hi ucef, cool to discuss with you" + DateTime.Now);
return View();
}
But exception occurred because auth.UserId is null, have you any idea?
This appears to be the same as your previous question:
Send Private message with LinqToTwitter
Joe

Resources