Set HTTPOnly cookie from the ASP.net Web Api - 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.

Related

Response for preflight is invalid (redirect) using 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!

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;
}
}
}

Return an HttpResponse in an APIController Method which calls a different API

I have an APIController Method as below. Basically I need to validate an API response. So it's an API call within an API call.
public class DCController : ApiController
{
[HttpPost]
public HttpResponseMessage SampleMethod(string url)
{
var uri = new Uri(url);
var baseAddress = uri.GetLeftPart(System.UriPartial.Authority);
var apiAddress = url.Replace(baseAddress + "/", "");
var responseString = string.Empty;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(baseAddress);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = client.GetAsync(apiAddress).Result;
if (response.IsSuccessStatusCode)
{
responseString = response.Content.ReadAsStringAsync().Result;
}
}
if (!string.IsNullOrEmpty(responseString) && responseString.ToString().Validate())
{
return Request.CreateResponse(HttpStatusCode.OK, "Validated");
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid");
}
}
Issue:
1. Request object is null in the return lines.
2. If i try creating a request object -
var request = new HttpRequestMessage();
It throws below error:
An exception of type 'System.InvalidOperationException' occurred in
System.Web.Http.dll but was not handled in user code
Additional information: The request does not have an associated
configuration object or the provided configuration was null.
Not sure what settings I need to add. I am relatively new to working with APIs. Any help is appreciated.
I could get it working by below code -
[HttpPost]
public HttpResponseMessage Get(string url)
{
string responseString = GetWebApiData(url); //Extracted the method
HttpResponseMessage response = new HttpResponseMessage();
if (!string.IsNullOrEmpty(responseString) && responseString.ToString().Validate())
{
response.ReasonPhrase = "Valid";
response.StatusCode = HttpStatusCode.OK;
}
else
{
response.ReasonPhrase = "Invalid";
response.StatusCode = HttpStatusCode.BadRequest;
}
return response;
}

How to send pre request before every request in windows phone 7

I want to send one pre request to my server before send every request. From that pre request I will receive the token from my server and than I have to add that token into all the request. This is the process.
I have try with some methods to achieve this. But I am facing one problem. That is, When I try to send pre request, it is processing with the current request. That mean both request going parallel.
I want to send pre request first and parse the response. After parsing the pre request response only I want to send that another request. But first request not waiting for the pre request response. Please let me any way to send pre request before all the request.
This is my code:
ViewModel:
`public class ListExampleViewModel
{
SecurityToken sToken = null;
public ListExampleViewModel()
{
GlobalConstants.isGetToken = true;
var listResults = REQ_RESP.postAndGetResponse((new ListService().GetList("xx","xxx")));
listResults.Subscribe(x =>
{
Console.WriteLine("\n\n..................................2");
Console.WriteLine("Received Response==>" + x);
});
}
}`
Constant Class for Request and Response:
`public class REQ_RESP
{
private static string receivedAction = "";
private static string receivedPostDate = "";
public static IObservable<string> postAndGetResponse(String postData)
{
if (GlobalConstants.isGetToken)
{
//Pre Request for every reusest
receivedPostDate = postData;
GlobalConstants.isGetToken = false;
getServerTokenMethod();
postData = receivedPostDate;
}
HttpWebRequest serviceRequest =
(HttpWebRequest)WebRequest.Create(new Uri(Constants.SERVICE_URI));
var fetchRequestStream =
Observable.FromAsyncPattern<Stream>(serviceRequest.BeginGetRequestStream,
serviceRequest.EndGetRequestStream);
var fetchResponse =
Observable.FromAsyncPattern<WebResponse>(serviceRequest.BeginGetResponse,
serviceRequest.EndGetResponse);
Func<Stream, IObservable<HttpWebResponse>> postDataAndFetchResponse = st =>
{
using (var writer = new StreamWriter(st) as StreamWriter)
{
writer.Write(postData);
writer.Close();
}
return fetchResponse().Select(rp => (HttpWebResponse)rp);
};
Func<HttpWebResponse, IObservable<string>> fetchResult = rp =>
{
if (rp.StatusCode == HttpStatusCode.OK)
{
using (var reader = new StreamReader(rp.GetResponseStream()))
{
string result = reader.ReadToEnd();
reader.Close();
rp.GetResponseStream().Close();
XDocument xdoc = XDocument.Parse(result);
Console.WriteLine(xdoc);
return Observable.Return<string>(result);
}
}
else
{
var msg = "HttpStatusCode == " + rp.StatusCode.ToString();
var ex = new System.Net.WebException(msg,
WebExceptionStatus.ReceiveFailure);
return Observable.Throw<string>(ex);
}
};
return
from st in fetchRequestStream()
from rp in postDataAndFetchResponse(st)
from str in fetchResult(rp)
select str;
}
public static void getServerTokenMethod()
{
SecurityToken token = new SecurityToken();
var getTokenResults = REQ_RESP.postAndGetResponse((new ServerToken().GetServerToken()));
getTokenResults.Subscribe(x =>
{
ServerToken serverToken = new ServerToken();
ServiceModel sm = new ServiceModel();
//Parsing Response
serverToken = extract(x, sm);
if (!(string.IsNullOrEmpty(sm.NetErrorCode)))
{
MessageBox.Show("Show Error Message");
}
else
{
Console.WriteLine("\n\n..................................1");
Console.WriteLine("\n\nserverToken.token==>" + serverToken.token);
Console.WriteLine("\n\nserverToken.pk==>" + serverToken.pk);
}
},
ex =>
{
MessageBox.Show("Exception = " + ex.Message);
},
() =>
{
Console.WriteLine("End of Process.. Releaseing all Resources used.");
});
}
}`
Here's couple options:
You could replace the Reactive Extensions model with a simpler async/await -model for the web requests using HttpClient (you also need Microsoft.Bcl.Async in WP7). With HttpClient your code would end up looking like this:
Request and Response:
public static async Task<string> postAndGetResponse(String postData)
{
if (GlobalConstants.isGetToken)
{
//Pre Request for every reusest
await getServerTokenMethod();
}
var client = new HttpClient();
var postMessage = new HttpRequestMessage(HttpMethod.Post, new Uri(Constants.SERVICE_URI));
var postResult = await client.SendAsync(postMessage);
var stringResult = await postResult.Content.ReadAsStringAsync();
return stringResult;
}
Viewmodel:
public class ListExampleViewModel
{
SecurityToken sToken = null;
public ListExampleViewModel()
{
GetData();
}
public async void GetData()
{
GlobalConstants.isGetToken = true;
var listResults = await REQ_RESP.postAndGetResponse("postData");
}
}
Another option is, if you want to continue using Reactive Extensions, to look at RX's Concat-method. With it you could chain the token request and the actual web request: https://stackoverflow.com/a/6754558/66988

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