to persist RefreshToken while authenticating using GoogleAuthorizationCodeFlow - google-plus

var REFRESH_TOKEN = System.Configuration.ConfigurationSettings.AppSettings["AdxToken"].ToString();
ClientSecrets secrets = new ClientSecrets()
{
ClientId = clienID,
ClientSecret = clientSecret
};
var token = new TokenResponse { RefreshToken = REFRESH_TOKEN };
var credentials = new UserCredential(new GoogleAuthorizationCodeFlow(
new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = secrets
}),
"user",
token);
I am using above method to authenticate client.I want to automate my process to run daily, the problem is the RefreshToken used in above code expires after every two days.
Below is the code to get RefreshToken
private OAuth2Authenticator<WebServerClient> CreateAuthenticator()
{
// Register the authenticator.
var provider = new WebServerClient(GoogleAuthenticationServer.Description);
provider.ClientIdentifier = ClientCredentials.ClientID;
provider.ClientSecret = ClientCredentials.ClientSecret;
var authenticator = new OAuth2Authenticator<WebServerClient>(provider, GetAuthentication);
//{ NoCaching = true }; // TODO(mlinder): Uncomment when CL is merged.
return authenticator;
}
private IAuthorizationState GetAuthentication(WebServerClient client)
{
// If this user is already authenticated, then just return the auth state.
IAuthorizationState state = AuthState;
if (state != null)
{
return state;
}
// Check if an authorization request already is in progress.
state = client.ProcessUserAuthorization(new HttpRequestInfo(HttpContext.Current.Request));
if (state != null && (!string.IsNullOrEmpty(state.AccessToken) || !string.IsNullOrEmpty(state.RefreshToken)))
{
// Store and return the credentials.
HttpContext.Current.Session["AUTH_STATE"] = _state = state;
return state;
}
OutgoingWebResponse response = client.PrepareRequestUserAuthorization(new[] { "https://www.googleapis.com/auth/adexchange.seller", "https://www.googleapis.com/auth/adexchange.seller.readonly" });
response.Headers["Location"] += "&access_type=offline&approval_prompt=force";
response.Send(); // Will throw a ThreadAbortException to prevent sending another response.
return null;
}
Is there any way to persist this RefreshToken as my task cant be automated without this?

Related

Authorize using JWT token still returning unauthorized

my startup.cs (asp.net core 5.0)
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddAuthentication (options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidAudience = "https://www.yogihosting.com",
ValidIssuer = "https://www.yogihosting.com",
ClockSkew = TimeSpan.Zero,// It forces tokens to expire exactly at token expiration time instead of 5 minutes later
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("MynameisJamesBond007"))
};
});
}
I am trying to invoke http://localhost:31254/Reservation which returns the list of flight reservation lists which I am tring to call from CallAPIController.cs
ReservationController.cs
[Authorize]
public IEnumerable<Reservation> Index()
{
return CreateDummyReservations();
}
[HttpGet]
public IEnumerable<Reservation> Get() => CreateDummyReservations();
public List<Reservation> CreateDummyReservations()
{
List<Reservation> rList = new List<Reservation> {
new Reservation { Id=1, Name = "Ankit", StartLocation = "New York", EndLocation="Beijing" },
new Reservation { Id=2, Name = "Bobby", StartLocation = "New Jersey", EndLocation="Boston" },
new Reservation { Id=3, Name = "Jacky", StartLocation = "London", EndLocation="Paris" }
};
return rList;
}
CallAPIController.cs
//entry point of the controller
public async Task<IActionResult> Index(string message)
{
ViewBag.Message = message;
var accessToken = GenerateJSONWebToken(); //generating the token
SetJWTCookie(accessToken); //setting the cookie
List<Reservation> list = await FlightReservation();
return RedirectToAction("Home");
}
private string GenerateJSONWebToken()
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("MynameisJamesBond007"));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: "https://www.yogihosting.com",
audience: "https://www.yogihosting.com",
expires: DateTime.Now.AddHours(3),
signingCredentials: credentials
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
private void SetJWTCookie(string token)
{
var cookieOptions = new CookieOptions
{
HttpOnly = true,
Expires = DateTime.UtcNow.AddHours(3),
};
Response.Cookies.Append("jwtCookie", token, cookieOptions);
}
public async Task<List<Reservation>> FlightReservation()
{
var jwt = Request.Cookies["jwtCookie"];
List<Reservation> reservationList = new List<Reservation>();
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwt);
//calling the reservation controller asynchronously but returning
unauthorised.
using (var response = await httpClient.GetAsync("http://localhost:31254/Reservation")) // change API URL to yours
{
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
string apiResponse = await response.Content.ReadAsStringAsync();
reservationList = JsonConvert.DeserializeObject<List<Reservation>>(apiResponse);
}
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
//return RedirectToAction("Index", new { message = "Please Login again" });
}
}
}
return reservationList;
}
When I call the reservation controller I get 401 unauthorised error, though. If i remove authorize attribute it works. The point is it is not recognising the JWT token or validating it properly. Am I missing anything?
Your problem is in this line :
SetJWTCookie(accessToken);
List<Reservation> list = await FlightReservation();
When you set the cookie, the response must be received in the browser to set the cookie in the browser to be sent in subsequent requests, but the response has not been sent to the browser yet and you call this method
await FlightReservation();
This method requests a cookie that has not yet been set in the browser and has not been sent to this request, so the received token is empty here
var jwt = Request.Cookies["jwtCookie"]; //cookie is null
And the unauthorized error returns, but if this request ends, there will be no problem in subsequent requests because the cookie is set in the browser. So with your code it will always return unauthoruzed in first Request.
But if all requests fail, see if you have set up UseAuthentication Middleware or not
app.UseRouting();
app.UseAuthentication(); //here
app.UseAuthorization();
You set the cookie in your SetJWTCookie(string token) method:
Response.Cookies.Append("jwtCookie", token, cookieOptions)
And you try to get the cookie in the FlightReservation() method:
var jwt = Request.Cookies["jwtCookie"];
your Request dosn't contain jwtCookie. so you can't get the value of your jwt
token
Just try as below:
[HttpPost]
public async Task<IActionResult> Authenticate(UserModel someuser)
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("MynameisJamesBond007"));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: "https://www.yogihosting.com",
audience: "https://www.yogihosting.com",
expires: DateTime.Now.AddHours(3),
signingCredentials: credentials
);
string jwtToken = new JwtSecurityTokenHandler().WriteToken(token);
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken);
var response = await httpClient.GetAsync(url); // change API URL to yours
}
return Content(jwtToken);
}
Result:

Asp.net core 6 mvc : Authorize controller methods with JWT token from external API

I am building a .Net core 6 mvc website which will interact with an API built by an external party. Amongst other things, the user authentication is handled by the API. The API responds with a JWT bearer token once user is authenticated and I need to tie that in to my website to Authorize controller methods.
At this point I call the API and successfully receive the token as expected, however after days of struggling to get [Authorize] to work in the controllers with the token, I am completely lost and hoping for some guidance.
After scrapping multiple iterations of code, this what I currently have.... (excuse the mess)
public async Task<TokenResponse> LoginAsync(string email, string password)
{
var userLogin = new UserLogin
{
Email = email,
Password = password
};
string encoded = System.Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(email + ":" + password));
var client = new RestClient("api location");
var request = new RestRequest();
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", "Basic " + encoded);
var response = await client.GetAsync(request);
var result = JsonConvert.DeserializeObject<TokenResponse>(response.Content);
return result;
}
public async Task<IActionResult> LoginPostAsync(LoginViewModel viewModel)
{
var tokenResponse = await _userManagementService
.LoginAsync(viewModel.Email, viewModel.Password);
if (!string.IsNullOrEmpty(tokenResponse.access_token))
{
var handler = new JwtSecurityTokenHandler();
var jwtSecurityToken = handler.ReadJwtToken(tokenResponse.access_token);
var jti = jwtSecurityToken.Claims.First(claim => claim.Type == "jti").Value;
var account_type = jwtSecurityToken.Claims.First(claim => claim.Type == "account_type").Value;
var userId = jwtSecurityToken.Claims.First(claim => claim.Type == "user_id").Value;
var email = jwtSecurityToken.Claims.First(claim => claim.Type == "email").Value;
var iss = jwtSecurityToken.Claims.First(claim => claim.Type == "iss").Value;
string[] userRoles = { "admin", "candidate",};
HttpContext context = new DefaultHttpContext();
var accessToken = tokenResponse.access_token;
//var userClaims = new List<Claim>()
// {
// new Claim("email", email),
// new Claim("account_type", account_type),
// new Claim("jti", jti),
// };
//var userIdentity = new ClaimsIdentity(userClaims, "User Identity");
//var userPrincipal = new ClaimsPrincipal(new[] { userIdentity });
//context.SignInAsync(userPrincipal);
//Response.Cookies.Append(
// Constants.XAccessToken,
// tokenResponse.access_token, new CookieOptions
// {
// Expires = DateTimeOffset.UtcNow.AddMinutes(1),
// HttpOnly = true,
// SameSite = SameSiteMode.Strict
// });
//return new AuthenticateResponse(user, token);
SetJWTCookie(accessToken);
return RedirectToAction("index", "Home", new { area = "CandidateDashboard" });
}
return Unauthorized();
}
Program.cs
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(config =>
{
config.SaveToken = true;
config.RequireHttpsMetadata = false;
config.TokenValidationParameters = new TokenValidationParameters()
{
ValidateAudience = false,
ValidateIssuer = true,
ValidIssuer = "issue data",
ValidateIssuerSigningKey = false,
};
config.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
context.Token = context.Request.Cookies["Bearer"];
return Task.CompletedTask;
}
};
});
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public IActionResult Index()
{
return View();
}
This is the what I see in dev console.
--bearer error="invalid_token", error_description="the signature key was not found"
Payload from Bearer
{
"iss": "data here",
"exp": 1647323406,
"nbf": 1647319746,
"iat": 1647319806,
"jti": "e8f297d3-blah blah",
"account_type": "candidate",
"user_id": "2342342342",
"email": "email#email.com"
}
The core problem is that AddJwtBearer by default only trusts token issued by someone it trusts (the issuer) because it needs to verify the signature of the token. You of course want to verify it so a hacker doesn't send fake/forged tokens to your API.
So either you need to add that
.AddJwtBearer(opt =>
{
opt.Authority = "https://issuer.com"
In this way, AddJwtBearer will download the public signing key automatically for you.
Or you need to add the public signing key manually to AddJwtBearer.
see https://devblogs.microsoft.com/dotnet/jwt-validation-and-authorization-in-asp-net-core/

User.Identity.Name is empty with JWT when method is no decorated with Authorize in Asp.NET Core 3.0 API Controller

I have a Web Api project in .net core 3.1 and I have added JwT authentication.
The authentication and authorization work very well, but I need to get the UserId in every request. When the method is decorated with Authorize attribute, this works well.
[HttpGet]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public IEnumerable<WeatherForecast> Get()
{
string user = User.Identity.Name; //Get a value
//Do something
}
However I have some method which authentication is not required, but if an authenticated user make a request, I would like to get the userId, but in this case, user.Identity.Name is always null.
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
string user = User.Identity.Name; //null
//Do somwthing
}
My configuration in statur file is:
private void ConfigureJwt(IServiceCollection services)
{
//Add Auth scheme
services.AddAuthorization(options =>
{
var defaultAuthorizationPolicyBuilder = new Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme);
defaultAuthorizationPolicyBuilder = defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
});
AuthSettings authSettings = Configuration.GetSection("AuthSettings").Get<AuthSettings>();
JwtIssuerOptions jwtIssuerOptions = Configuration.GetSection("JwtIssuerOptions").Get<JwtIssuerOptions>();
services.AddAuthentication(opt =>
{
opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtIssuerOptions.Issuer,
ValidAudience = jwtIssuerOptions.Audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authSettings.SecretKey))
};
options.Events = new JwtBearerEvents
{
OnTokenValidated = context =>
{
//When method is no decorated with Authorize, it not working
var userId = int.Parse(context.Principal.Identity.Name);
return System.Threading.Tasks.Task.CompletedTask;
}
};
});
services.AddTransient<ITokenService, TokenService>(x =>
{
return new TokenService(Configuration);
});
}
TokenService class:
public class TokenService : ITokenService
{
IConfiguration configuration = null;
AuthSettings authSettings = null;
public TokenService(IConfiguration _configuration)
{
configuration = _configuration;
authSettings = configuration.GetSection("AuthSettings").Get<AuthSettings>();
}
public string GenerateAccessToken(IEnumerable<Claim> claims, ref JwtIssuerOptions jwtIssuerOptions)
{
//var authSettings = configuration.GetSection(nameof(AuthSettings));
//var authSettings = configuration.GetSection("EmailSettings").Get<AuthSettings>();
jwtIssuerOptions = configuration.GetSection("JwtIssuerOptions").Get<JwtIssuerOptions>();
var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authSettings.SecretKey));
var signinCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);
var tokeOptions = new JwtSecurityToken (
issuer: jwtIssuerOptions.Issuer,
audience: jwtIssuerOptions.Audience,
claims: claims,
expires: jwtIssuerOptions.Expiration,
//expires: DateTime.Now.AddMinutes(5),
signingCredentials: signinCredentials
);
var tokenString = new JwtSecurityTokenHandler().WriteToken(tokeOptions);
return tokenString;
}
public string GenerateRefreshToken()
{
var randomNumber = new byte[32];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(randomNumber);
return Convert.ToBase64String(randomNumber);
}
}
public ClaimsPrincipal GetPrincipalFromExpiredToken(string token)
{
TokenValidationParameters tokenValidationParameters = GetValidationParameters();
var tokenHandler = new JwtSecurityTokenHandler();
SecurityToken securityToken;
var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out securityToken);
var jwtSecurityToken = securityToken as JwtSecurityToken;
if (jwtSecurityToken == null || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
throw new SecurityTokenException("Invalid token");
return principal;
}
private TokenValidationParameters GetValidationParameters()
{
var tokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false, //you might want to validate the audience and issuer depending on your use case
ValidateIssuer = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authSettings.SecretKey)),
ValidateLifetime = false //here we are saying that we don't care about the token's expiration date
};
return tokenValidationParameters;
}
}
AuthController
[HttpPost, Route("login")]
public async Task<IActionResult> Login([FromBody] LoginModel loginModel)
{
if (loginModel == null)
return BadRequest("Invalid client request");
var sessionInfo = await userBo.LoginUser(loginModel);
if (sessionInfo == null)
return Unauthorized();
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, sessionInfo.User.BusinessEntityId.ToString()),
new Claim(ClaimTypes.Role, sessionInfo.User.RoleCode)
};
JwtIssuerOptions tokeOptions = null;
var accessToken = tokenService.GenerateAccessToken(claims, ref tokeOptions);
var refreshToken = tokenService.GenerateRefreshToken();
await tokenBo.SaveToken(
new Token()
{
BusinessEntityId = sessionInfo.Person.BusinessEntityId,
RefreshToken = refreshToken,
RefreshTokenExpiryTime = tokeOptions.Expiration
}
);
sessionInfo.TokenInfo = new TokenInfo()
{
AccessToken = accessToken,
RefreshToken = refreshToken
};
return Ok(sessionInfo);
}
}
Thank you for your help!
As far as I know, if the controller doesn't need authorize, it will not add the user information into pipeline claims, so the user name is always null.
To solve this issue, I suggest you could try to add a custom middleware to check if the request contains the Authorization header. If it contains you could get the username and add it into http context item.
Then you could directly get the username in the api controller instead of getting it from User.Identity.Name.
More details, you could refer to below codes:
Add below middleware into startup.cs Configure method:
app.Use(async (context, next) =>
{
// you could get from token or get from session.
string token = context.Request.Headers["Authorization"];
if (!string.IsNullOrEmpty(token))
{
var tok = token.Replace("Bearer ", "");
var jwttoken = new JwtSecurityTokenHandler().ReadJwtToken(tok);
var jti = jwttoken.Claims.First(claim => claim.Type == ClaimTypes.Name).Value;
context.Items.Add("Username", jti);
}
await next();
});
Controller get the username:
object value;
ControllerContext.HttpContext.Items.TryGetValue("Username", out value);
var username = value.ToString();
Result:
After changing an application from using cookie-based authentication to using JWT I ran into this problem. You can work around it — sort of — by creating an authorization handler with no requirements thus allowing anonymous users access. The ASP.NET pipeline doesn't know which requirements will be required so it will provide the credentials of the user if they are present in the request. The end result is that anonymous users are allowed but if credentials are provided they will be available.
The trivial requirement:
class RequireNothing : IAuthorizationRequirement { }
And the handler:
class RequireNothingHandler : AuthorizationHandler<RequireNothing>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RequireNothing requirement)
{
context.Succeed(requirement);
return Task.CompletedTask;
}
}
If the request contains credentials they will become available in the User object but the requirement also allow anonymous users access.
To use the requirement you can create a policy (and also add the handler to the DI container):
services
.AddAuthorization(options => options
.AddPolicy("AlsoAllowAnonymous", policy => policy
.AddRequirements(new RequireNothing())))
.AddSingleton<IAuthorizationHandler, RequireNothingHandler>();
To combine authenticated and anonymous access you decorate the action or controller with the attribute:
[Authorize(Policy = "AlsoAllowAnonymous")]
Unfortunately, this might not work so well. If you are using a long-lived JWT refresh tokens and short-lived access tokens that are refreshed when a 401 challenge is received there will be no challenge after the access token expires and the user will access the end-point anonymously possibly resulting in a degraded user experience even though the user has authenticated and has a refresh token to prove that.
This problem is not unique to using an authorization handler and you get more control by providing two different end-points: one for anonymous users and another one for authenticated users. You need some extra logic on the client side to select the correct API for things to work out right though.

How can I get access_token after logged in IdentityServer with asp.net

After using Facebook access_token and userId to get Facebook information and use email to login/register Identity Server account, I want to get the access_token of Identity Server account to login the main server account.
It might be contained the sub (user id) however I cannot use the userManager's method to find the token.
Here is my sample code for getting access_token but both not work:
[HttpPost]
[AllowAnonymous]
public async Task<string> GetTokenForIOS(FacebookUserModel model)
{
model.email = await GetEmail(model);
var user = await _userManager.FindByNameAsync(model.email);
var userInfo = _userManager.Users.SingleOrDefault(x => x.Email == model.email);
if (user != null)
{
// sign in identityServer
await _signInManager.SignInAsync(user, isPersistent: false);
// the first way to get access_token
var externalAccessToken = await _userManager.GetAuthenticationTokenAsync(user, "Facebook", "access_token");
// the second way to get access_token
string token = await GetAccessToken();
//return access_token
return token;
}
return "";
}
public async Task<string> GetAccessToken()
{
// discover endpoints from metadata
var disco = await DiscoveryClient.GetAsync("https://localhost:44355");
// request token
var tokenClient = new TokenClient(disco.TokenEndpoint, "client.ios");
var tokenResponse = await tokenClient.RequestClientCredentialsAsync("api");
if (tokenResponse.IsError)
{
return "";
}
else
{
Console.WriteLine(tokenResponse.Json);
JToken jObject = tokenResponse.Json;
return tokenResponse.Json.ToString();
}
}
Here is my client config:
new Client
{
ClientId = "client.ios",
RequireClientSecret = false,
ClientName = "iOS app client",
AllowedGrantTypes = GrantTypes.Code,
RequirePkce = true,
RequireConsent = false,
RedirectUris = { "net.openid.appauthdemo:/oauth2redirect" },
PostLogoutRedirectUris = { "net.openid.appauthdemo:/oauth2redirect" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
IdentityServerConstants.StandardScopes.Phone,
"api"
},
AllowOfflineAccess = true
}
Is there any way can help me to find the user access_token for token response in this scenario?

KnockoutJS + WebAPI 2 Token Authentication - maintain login state until token expires

I'm fairly new to token based authentication and I have a problem of how to maintain login state after I login.
I want to create a SPA website for which I am using Knockoutjs for my front end and SammyJS for routing and changing the views.
After I login in and get the token I store it in localStorage and set the username into an observable which I am displaying.
My problem is that after I close the tab or browser and I go back to the site, the token is in the localStorage but I can't see the user logged in.
I want to maintain the login state until the token expires. My question is what should I do with the token from the localStorage when I enter the site in order to maintain the login state of that user?
Do I need to make something in the startup class or to check if that user exists in the DB?
Thanks in advance!
Here is my code:
StartupAuth.cs
[assembly: OwinStartup(typeof(EventHub.PL.WebUI.Startup))] namespace EventHub.PL.WebUI {
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get;private set; }
public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
public const string TokenEndpointPath = "/api/token";
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.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString(TokenEndpointPath),
Provider = new ApplicationOAuthProvider(PublicClientId),
//AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
//app.UseOAuthBearerTokens( OAuthOptions );
app.UseOAuthAuthorizationServer(OAuthOptions);
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
}
}
AccountController.cs
[HttpPost]
[AllowAnonymous]
[Route("Login")]
public async Task<IHttpActionResult> Login(LoginUser model)
{
var request = HttpContext.Current.Request;
var tokenServiceUrl = request.Url.GetLeftPart(UriPartial.Authority) + request.ApplicationPath + "/api/Token";
using (var client = new HttpClient())
{
var requestParams = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("username", model.Email),
new KeyValuePair<string, string>("password", model.Password)
};
var requestParamsFormUrlEncoded = new FormUrlEncodedContent(requestParams);
var tokenServiceResponse = await client.PostAsync(tokenServiceUrl, requestParamsFormUrlEncoded);
var responseString = await tokenServiceResponse.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<TokenResponse>(responseString);
var responseCode = tokenServiceResponse.StatusCode;
if (responseCode == HttpStatusCode.OK)
{
RegisterUser user = userRepository.GetNameById(json.Id);
var data = new
{
status = "success",
json.access_token,
user.Lastname
};
return Json(data);
}
return Json(new { status = "failed" });
}
}
here is the KO part:
var LoginApp = function () {
var instance = this;
instance.mainViewModel = new MainViewModel();
instance.loginViewModel = new LoginViewModel();
instance.loginRepository = new LoginRepository();
instance.loginViewModel.signIn = function() {
$('.loader-header').show();
var postData = {
email: instance.loginViewModel.email(),
password: instance.loginViewModel.password
}
instance.loginRepository.SignIn(SignInSuccess, postData);
};
instance.SignInSuccess = function(response) {
if (response.status === 'success') {
instance.mainViewModel.username(response.Lastname);
instance.mainViewModel.isVisible(true);
var userData = {
token: response.access_token,
username: response.Lastname
};
localStorage.setItem('AuthorizationData', JSON.stringify(userData));
$('.loader-header').hide();
dialog.close();
} else {
$('.loader-header').hide();
}
};
instance.init = function () {
ko.applyBindings(instance.loginViewModel, document.getElementById("signin-form"));
ko.applyBindings(instance.mainViewModel, document.getElementById("main-wrapper"));
}
instance.init();
}
$(document).ready(function () {
var loginApp = LoginApp();
});
UPDATE
here is my routing also
var appRoot = root;
(function ($) {
var app = $.sammy('#page', function () {
this.get('#/home', function (context) {
document.title = 'Home - ' + title;
var url = getUrlFromHash(context.path);
loadView(url, new MainViewModel(), MainApp);
//context.load(url).swap();
});
this.get('#/about', function (context) {
var url = getUrlFromHash(context.path);
loadView(url, new AboutViewModel(), AboutApp);
});
this.get('#/manage', function (context) {
var url = getUrlFromHash(context.path);
loadView(url, new AboutViewModel(), AboutApp);
});
});
$(function () {
app.run('#/home');
});
})(jQuery);
function loadView(url, viewModel, callback) {
$.get(url, function (response) {
var $container = $('#page');
//var $view = $('#page').html(response);
$container.html(response);
callback();
});
}
function getUrlFromHash(hash) {
var url = hash.replace('#/', '');
if (url === appRoot)
url = 'home';
return url;
}
Right now all you're doing is storing the user's credentials in localStorage but not using them to perform authorization. One alternative is to use the Sammy.OAuth2 plugin (which you can find it here).
You can define a route to make the authentication like:
app.post("#/oauth/login", function(context) {
this.load('http://yourwebsite/login',
{
cache: false,
type: 'post',
data: {
email: $("input[name=email]").val(),
password: $("input[name=password]").val()
}
})
.then(function(content) {
if(content != false){
if(app.getAccessToken() == null){
app.setAccessToken(token());
}
}else{
app.trigger("oauth.denied");
return false;
}
});
});
In 'protected' routes you can check if the user is already logged in like this:
app.get("#/profile", function(context) {
if(app.getAccessToken() != null)
context.render('view/profile.template');
else
this.requireOAuth();
});
This examples will have to be modified to populate the token according to your scenario. Here's a complete tutorial on Sammy.Oath2.