Xamarin iOS Oidc downloads webpage after login - ios

I have an app that uses Oidc to login. This works fine in most cases. But there is one iphone 8+ running iOS 15.6.1 that keeps downloading the return url from the login request.
i use Xamarin forms v 5.0.0.2515, Xamarin.Essentials 1.7.3, Xamarin.CommunityToolkit 2.0.5
IdentityModel.OidcClient 3.1.2
The problem is that it works on all other devices and i can't replicate it in a dev environment.
public class WebauthenticatorBrowser : IBrowser
{
private readonly string callbackUrl;
public WebauthenticatorBrowser(string? callbackUrl = null)
{
this.callbackUrl = callbackUrl;
}
public async Task<BrowserResult> InvokeAsync(BrowserOptions options, CancellationToken cancellationToken = default)
{
try
{
var callBack = string.IsNullOrWhiteSpace(callbackUrl) ? options.EndUrl : callbackUrl;
var authResult = await WebAuthenticator.AuthenticateAsync(new WebAuthenticatorOptions
{
Url = new Uri(options.StartUrl),
CallbackUrl = new Uri(callBack),
PrefersEphemeralWebBrowserSession = false
});
var authorizeResponse = ToRawIdentityUrl(options.EndUrl, authResult);
return new BrowserResult()
{
Response = authorizeResponse
};
}
catch (Exception ex)
{
return new BrowserResult()
{
Error = ex.Message
};
}
}
private string ToRawIdentityUrl(string redirectUrl, WebAuthenticatorResult result)
{
IEnumerable<string> parameters = result.Properties.Select(x => $"{x.Key}={x.Value}");
var values = string.Join("&", parameters);
return $"{redirectUrl}#{values}" ;
}
}
In my oidc class where i create my client
private async Task createOidcClient() {
document = await httpClient.GetDiscoveryDocumentAsync(idsUrl);
if (document.IsError) {
alertPresenter.Alert("Connection issue", "please try again");
return;
}
var options = new OidcClientOptions {
Authority = document.Issuer,
ClientId = "---clientID-",
Scope = "-- all the scopes --",
RedirectUri = "-- callback url--",
PostLogoutRedirectUri = " -- callback url--",
Browser = new WebauthenticatorBrowser(),
ResponseMode = OidcClientOptions.AuthorizeResponseMode.Redirect
};
client = new OidcClient(options);
}
the login call in the OicdClass
public async Task<LoginResult> Login() {
await createOidcClient();
var result = await client.LoginAsync(new LoginRequest());
if (result.IsError) return result;
setAuthHeader(result.AccessToken);
await accessTokenUpdater.SetAllTokens(result.AccessToken, result.RefreshToken, result.IdentityToken);
return result;
}

Related

.Net Core JWT + cookie auth on Web API and MVC Web Project invalid signature

My application first uses cookie auth to login. I then have it calling an API which I would like to use JWT auth which opens a websocket stream (Im debating and putting this stream on the UI) when the API gets an update it calls the UI and I want this one call to be a JWT Auth, I tried a bunch of things this past weekend but I keep getting invalid signature or SSL cert is invalid.
Both projects are .Net Core. One is a web api and the other is a MVC project
Its actually 2 APIS and MVC (userAPI, TraderAPI and the UI)
User API
public string GenerateJWTToken(UserRoleVM user)
{
if (user != null)
{
var secretKey = Base64UrlEncoder.DecodeBytes(_config.GetSection("Tokens:Key").ToString());
var securityKey = new SymmetricSecurityKey(secretKey);
var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
var currentTime = DateTime.Now;
var claims = new Claim[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.UserName)
,new Claim(JwtRegisteredClaimNames.Sid, user.UserGUID)
,new Claim(JwtRegisteredClaimNames.NameId, user.UserID.ToString())
,new Claim(JwtRegisteredClaimNames.Email, user.Email)
,new Claim(JwtRegisteredClaimNames.AuthTime, currentTime.ToString())
,new Claim(ClaimTypes.Role, user.Role)
//,new Claim(JwtRegisteredClaimNames.)
,new Claim(type: "Subscribed", value: user.IsSubscribed.ToString())
,new Claim(type: "SubscribedDate", value: user.DateSubscribed.ToString())
};
var jwtSecurityToken = new JwtSecurityToken
(
signingCredentials: signingCredentials,
audience: _config.GetValue<string>("Tokens:Audience"),
issuer: _config.GetValue<string>("Tokens:Issuer"),
expires: currentTime.AddMinutes(_config.GetValue<int>("Tokens:LifeTime")),
//notBefore: currentTime,
claims: claims
);
return new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
}
return null;
}
//public Task<LoginResponseVM> Login(string username, string password)
public async Task<string> Login(string username, string password)
{
string jwtToken = null;
if (!string.IsNullOrWhiteSpace(username) && !string.IsNullOrWhiteSpace(password))
{
try
{
var result = await _signInManager.PasswordSignInAsync(username, password, false, false);
if (result.Succeeded)
{
//var savedUser = await _userService.GetUserByNameAsync(username);
//var role = await _userService.GetUserRolesAsync(savedUser);
var userVM = await _userService.GetUserNRole2Async(username);
//jwtToken = Convert.ToBase64String(Encoding.ASCII.GetBytes(GenerateJWTToken(userVM)));
jwtToken = GenerateJWTToken(userVM);
}
}
catch (Exception ex)
{
}
}
return jwtToken;
}
TraderAPI
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[HttpPost]
//public async Task<IActionResult> GetTradeStatusUpdate([FromBody] TradeResultVM model)
public async Task<IActionResult> SendTradeStatusUpdate([FromBody] TradeResultVM model)
{
_logger.LogInformation("Inside GetTradeStatus");
var lstTradeStatuses = await GetLstTradeStatuses();
if (lstTradeStatuses != null)
{
await _semaphoreSlimS.WaitAsync();
try
{
foreach (var activeTrade in lstTradeStatuses)
{
if (activeTrade.TradeID == model.TradeID)
{
_logger.LogInformation("Trade found in lstTradeStatuses");
...
}
[HttpPost("SendUITradeStatusV4")]
public async Task<IActionResult> SendUITradeStatusV4(BinanceStreamOrderUpdate orderUpdate, string token)
{
if (orderUpdate != null)
{
TradeResultVM tradeVM = new TradeResultVM
{
//TradeName = "Test",
TradeID = orderUpdate.OrderId,
TradeSymbol = orderUpdate.Symbol,
Price = orderUpdate.Price,
Quantity = orderUpdate.Quantity
};
string trade = JsonSerializer.Serialize(tradeVM);//
using var client = _httpClient.CreateClient("TraderUI");
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
//client.BaseAddress = new Uri("https://localhost:50111");
//using var response = await client.PostAsync($"/HarkinsTrader/GetTradeStatusUpdate/",
_logger.LogInformation("Sending Key");
using var response = await client.PostAsync($"/HarkinsTrader/SendTradeStatusUpdate/",
new StringContent(trade, Encoding.UTF8, "application/json"));
if (response.IsSuccessStatusCode)
{
_logger.LogInformation("Success StreamStatus Update");
return Ok();
}
}
return BadRequest();
}

skipped queue in MassTransit with RabbitMQ in dot net core application

I have three projects. One is Dot net core MVC, two are API projects. MVC is calling one API for user details. When user details are asked, I am sending message to queue through MassTransit. I am seeing skipped queue. There's consumer in third project which is API project.
I tried to make another solution for a demo with same configuration. It's running fine.
Below is MVC Razor page code..
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
ReturnUrl = returnUrl;
if (ModelState.IsValid)
{
var user = await AuthenticateUser(Input.Email);
if (user == null)
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return Page();
}
#region snippet1
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, user.Email),
new Claim("FullName", user.FullName),
new Claim(ClaimTypes.Role, "Administrator"),
};
var claimsIdentity = new ClaimsIdentity(
claims, CookieAuthenticationDefaults.AuthenticationScheme);
var authProperties = new AuthenticationProperties
{
ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(15),
IsPersistent = true,
};
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity),
authProperties);
#endregion
_logger.LogInformation("User {Email} logged in at {Time}.",
user.Email, DateTime.UtcNow);
return LocalRedirect(Url.GetLocalUrl(returnUrl));
}
return Page();
}
private async Task<ApplicationUser> AuthenticateUser(string email)
{
if (!string.IsNullOrEmpty(email))
{
using (var client = new System.Net.Http.HttpClient())
{
var request = new System.Net.Http.HttpRequestMessage();
request.RequestUri = new Uri("http://localhost:52043/api/user?uName=" + email); // ASP.NET 3 (VS 2019 only)
var response = await client.SendAsync(request);
var customer = Newtonsoft.Json.JsonConvert.DeserializeObject<Customers>(response.Content.ReadAsStringAsync().Result);
return new ApplicationUser()
{
Email = email,
FullName = customer.FullName
};
}
}
else
{
return null;
}
}
MVC Startup:
services.AddMassTransit(x =>
{
x.AddBus(provider => Bus.Factory.CreateUsingRabbitMq(cfg =>
{
// configure health checks for this bus instance
cfg.UseHealthCheck(provider);
cfg.Host("rabbitmq://localhost");
}));
});
services.AddMassTransitHostedService();
User API Code - 52043:
[HttpGet]
public async Task<IActionResult> Get(string uName)
{
var customer = _userRepository.GetCustomerByUserName(uName);
Uri uri = new Uri("rabbitmq://localhost/loginqueue");
var endpoint = await _bus.GetSendEndpoint(uri);
await endpoint.Send(new LoginObj() { NoteString = customer.FullName + " has logged in at " + DateTime.Now.ToString() });
return Json(customer);
}
Logging API - Consumer Code:
public class LoginConsumer : IConsumer<LoginObj>
{
private readonly ILogger<object> _logger;
public LoginConsumer(ILogger<object> logger)
{
_logger = logger;
}
public async Task Consume(ConsumeContext<LoginObj> context)
{
var data = context.Message;
_logger.LogInformation(data.ToString());
}
}
Login API Startup:
services.AddMassTransit(x =>
{
x.AddConsumer<LoginConsumer>();
x.AddBus(provider => Bus.Factory.CreateUsingRabbitMq(cfg =>
{
// configure health checks for this bus instance
cfg.UseHealthCheck(provider);
cfg.Host("rabbitmq://localhost");
cfg.ReceiveEndpoint("loginqueue", ep =>
{
ep.PrefetchCount = 16;
ep.UseMessageRetry(r => r.Interval(2, 100));
ep.ConfigureConsumer<LoginConsumer>(provider);
});
}));
});
services.AddMassTransitHostedService();
As per the documentation:
MassTransit uses the full type name, including the namespace, for message contracts. When creating the same message type in two separate projects, the namespaces must match or the message will not be consumed.
Make sure that your message type has the same namespace/type in each project.

Not receiving access_token in three-legged oauth 2.0 flow in asp.net mvc (Blackboard Learn)

I have to implement three-legged authentication in ASP.NET MVC. I have followed the steps according to the Blackboard documentation, especially the link https://community.blackboard.com/docs/DOC-3976-three-legged-oauth
I have received authorization code by calling the REST API /learn/api/public/v1/oauth2/authorizationcode.After that according to the documentation (I followed the documentation exactly but I don't know what am I have been missing ), I built a POST request to /learn/api/public/v1/oauth2/token to get access_token but I am unable to get access_token.
Instead, access_token, I have been receiving a BadRequest. This means I am making a mistake to build my second request but I am unable to fix the problem. I haven't found any code sample in .NET to implement three legged authentication for Blackboard Learn. Could you please help me to resolve the issue?
This is my code to call both APIs to receive access_token.
public class HomeController : Controller
{
public ActionResult Index()
{
// GET /learn/api/public/v1/oauth2/authorizationcode
Guid stateId = Guid.NewGuid();
string applicationKey = "Application key goes here";
string redirectUrl = string.Format("https://Blackboard Learn URL goes here/learn/api/public/v1/oauth2/authorizationcode" +
"?redirect_uri=https://localhost:44300/Home/OAuth2Response&response_type=code&client_id={0}&scope=read&state={1}",
applicationKey, stateId);
Response.Redirect(redirectUrl, true);
return View();
}
public async Task<bool> OAuth2Response(string code = null, string state = null, string error = null, string error_description = null)
{
bool success = true;
string json = string.Empty;
string urlCommand = string.Format("/learn/api/public/v1/oauth2/token?code={0}&redirect_url=https://localhost:44300/Home/OAuth2Response", code);
try
{
using (HttpClient client = new HttpClient())
{
var endpoint = new Uri("Blackboard Learn URL goes here" + urlCommand);
var postData = new List<KeyValuePair<string, string>>();
postData.Add(new KeyValuePair<string, string>("grant_type", "authorization_code"));
HttpContent body = new FormUrlEncodedContent(postData);
// POST /learn/api/public/v1/oauth2/token
using (HttpResponseMessage response = await client.PostAsync(endpoint, body)) // Problem is here
{
if (response.IsSuccessStatusCode)
{
json = await response.Content.ReadAsStringAsync();
}
else
{
success = false;
}
}
}
}
catch (Exception err)
{
//hopefully we never end up here, log this exception for forensics
success = false;
}
return success;
}
}
NOTE: I can successfully receive an access_token in Postman tool.
Finally, the below code works perfectly for 3 legged authentications in ASP.NET MVC.
public class HomeController : Controller
{
//https://blackboard.jiveon.com/docs/DOC-3976-three-legged-oauth
public ActionResult Index()
{
// GET /learn/api/public/v1/oauth2/authorizationcode
Guid stateId = Guid.NewGuid();
string applicationKey = "Application key goes here";
string redirectUrl = string.Format("Blackboard Learn URL goes here/learn/api/public/v1/oauth2/authorizationcode" +
"?redirect_uri=https://localhost:44300/Home/OAuth2Response&response_type=code&client_id={0}&scope=read&state={1}",
applicationKey, stateId);
Response.Redirect(redirectUrl, true);
return View();
}
public async Task<bool> OAuth2Response(string code = null, string state = null, string error = null, string error_description = null)
{
bool success = true;
string json = string.Empty;
string urlCommand = string.Format("/learn/api/public/v1/oauth2/token?code={0}&redirect_uri=https://localhost:44300/Home/OAuth2Response", code);
try
{
using (HttpClient client = new HttpClient())
{
var endpoint = new Uri("Blackboard Learn URL goes here" + urlCommand);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes("client_id:client_secret")));
var postData = new List<KeyValuePair<string, string>>();
postData.Add(new KeyValuePair<string, string>("grant_type", "authorization_code"));
HttpContent body = new FormUrlEncodedContent(postData);
using (HttpResponseMessage response = await client.PostAsync(endpoint, body))
{
if (response.IsSuccessStatusCode)
{
json = await response.Content.ReadAsStringAsync();
dynamic oauth2Result = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
string access_token = oauth2Result.access_token;
string refresh_token = oauth2Result.refresh_token; }
else
{
success = false;
}
}
}
}
catch (Exception err) {
//hopefully we never end up here, log this exception for forensics
success = false;
}
return success;
}
}

JWT Authentication ASP.NET Core MVC application

I've seen numerous examples of how to use JWT authentication with Angular, React, Vue etc... clients but can't find any examples of using JWT authentication with ASP.NET Core (specifically 2.2) Web App Mvc.
Does anyone have any examples or advice on how to do this?
Thanks,
You can use this class based on nuget package JWT 3.0.3
using JWT;
using JWT.Algorithms;
using JWT.Serializers;
using Newtonsoft.Json;
using System;
namespace Common.Utils
{
public class JwtToken
{
private IJwtEncoder encoder;
private IJwtDecoder decoder;
/// <remarks>
/// This requires a key value randomly generated and stored in your configuration settings.
/// Consider that it is a good practice use keys as at least long as the output digest bytes
/// length produced by the hashing algorithm used. Since we use an HMAC-SHA-512 algorithm,
/// then we can provide it a key at least 64 bytes long.
/// <see cref="https://tools.ietf.org/html/rfc4868#page-7"/>
/// </remarks>
public string SecretKey { get; set; }
public JwtToken()
{
IJwtAlgorithm algorithm = new HMACSHA512Algorithm();
IJsonSerializer serializer = new JsonNetSerializer();
IDateTimeProvider datetimeProvider = new UtcDateTimeProvider();
IJwtValidator validator = new JwtValidator(serializer, datetimeProvider);
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
decoder = new JwtDecoder(serializer, validator, urlEncoder);
SecretKey = "";
}
public JwtToken(string secretKey) : this()
{
SecretKey = secretKey;
}
public bool IsTokenValid(string token)
{
return !string.IsNullOrWhiteSpace(DecodeToken(token));
}
public string GetToken(object payload)
{
try
{
return encoder.Encode(payload, SecretKey);
}
catch (Exception)
{
return encoder.Encode(new DataModel(payload), SecretKey);
}
}
public string DecodeToken(string token)
{
try
{
if (string.IsNullOrWhiteSpace(token) || token == "null")
{
return null;
}
return decoder.Decode(token, SecretKey, true);
}
catch (TokenExpiredException)
{
return null;
}
catch (SignatureVerificationException)
{
return null;
}
}
public T DecodeToken<T>(string token) where T : class
{
try
{
if (string.IsNullOrWhiteSpace(token))
{
return null;
}
return decoder.DecodeToObject<T>(token, SecretKey, true);
}
catch (TokenExpiredException)
{
return null;
}
catch (SignatureVerificationException)
{
return null;
}
catch (Exception)
{
var data = decoder.DecodeToObject<DataModel>(token, SecretKey, true).Data;
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(data));
}
}
}
public class DataModel
{
public DataModel(object data)
{
Data = data;
}
public object Data { get; set; }
}
}
Then in your Startup class Configure method set the jwt middleware
for check authentication status of each request:
app.Use((context, next) =>
{
// verify app access token if not another service call
var appAccessToken = context.Request.Headers["Authorization"];
if (appAccessToken.Count == 0)
{
context.Items["User"] = null;
}
else
{
var token = appAccessToken.ToString().Replace("Bearer ", "");
var jwtToken = new JwtToken(config.JwtTokenSecret); //you need a secret (with requirements specified above) in your configuration (db, appsettings.json)
if (string.IsNullOrWhiteSpace(token) || !jwtToken.IsTokenValid(token))
{
context.Response.StatusCode = 401;
return Task.FromResult(0);
}
dynamic user = jwtToken.DecodeToken<dynamic>(token);
var cachedToken = cache.Get(user.Id); //you need some cache for store your token after login success and so can check against
if (cachedToken == null || cachedToken.ToString() != token)
{
context.Response.StatusCode = 401;
return Task.FromResult(0);
}
context.Items["User"] = new Dictionary<string, string>() {
{ "FullName",user.Name?.ToString()},
{ "FirstName",user.FirstName?.ToString()},
{ "LastName",user.LastName?.ToString()},
{ "Role",user.Role?.ToString()},
{ "Email",user.Email?.ToString()}
};
}
return next();
});
And finally you need generate the token and return it after
authentication:
[AllowAnonymous]
public IActionResult Login(string username, string password)
{
User user = null; //you need some User class with the structure of the previous dictionary
if (checkAuthenticationOK(username, password, out user)) //chackAuthenticationOk sets the user against db data after a succesfull authentication
{
var token = new JwtToken(_config.JwtTokenSecret).GetToken(user); //_config is an object to your configuration
_cache.Set(user.id, token); //store in the cache the token for checking in each request
return Ok(token);
}
return StatusCode(401, "User is not authorized");
}
Add following code to startup
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Issuer"],
ValidAudience = Configuration["Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["SigningKey"]))
};
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env,, ILoggerFactory loggerFactory)
{
app.UseAuthentication();
}
Code for login action in AccountController
[Route("api/[controller]")]
public class AccountController : Controller
{
[AllowAnonymous]
[HttpPost]
[Route("login")]
public IActionResult Login([FromBody]LoginViewModel loginViewModel)
{
if (ModelState.IsValid)
{
var user = _userService.Authenticate(loginViewModel);
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, loginViewModel.Username),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
};
var token = new JwtSecurityToken
(
issuer: _configuration["Issuer"],
audience: _configuration["Audience"],
claims: claims,
expires: DateTime.UtcNow.AddDays(10),
notBefore: DateTime.UtcNow,
signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["SigningKey"])),
SecurityAlgorithms.HmacSha256)
);
return Ok(new
{
access_token = new JwtSecurityTokenHandler().WriteToken(token),
expires_in = (int)token.ValidTo.Subtract(DateTime.UtcNow).TotalSeconds,// TimeSpan.FromTicks( token.ValidTo.Ticks).TotalSeconds,
sub = loginViewModel.Username,
name = loginViewModel.Username,
fullName = user.FullName,
jobtitle = string.Empty,
phone = string.Empty,
email = user.EmailName,
});
}
}
}
I assume you have implemented JWT on the server side. To handle this on client side, first you have to add token to web browser local storage. Add to your main layout javascript (let's named it AuthService.js)
below code adds token to local storage after login button clicked. gettokenfromlocalstorage() retrieve token from local storage.
<script>
var token = "";
function Loginclick() {
var form = document.querySelector('form');
var data = new FormData(form);
var authsevice = new AuthService();
authsevice.LogIn(data.get("username").toString(), data.get("password").toString());
}
function gettokenfromlocalstorage() {
var authserv = new AuthService();
var mytoken = authserv.getAuth();
authserv.LogOut();
}
var AuthService = /** #class */ (function () {
function AuthService() {
this.authKey = "auth";
}
AuthService.prototype.LogIn = function (username, password) {
this.username = username;
this.password = password;
this.grant_type = "password";
this.client_id = "MyClientId";
var loginurl = "/api/Token/Auth";
var xhr = new XMLHttpRequest();
xhr.open("POST", loginurl, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(this));
xhr.onreadystatechange = function () {
console.log("onreadystatechange");
};
xhr.onerror = function () {
var aaa = this.responseText;
};
xhr.onload = function () {
var data = JSON.parse(this.responseText);
var auth = new AuthService();
auth.setAuth(data);
};
};
AuthService.prototype.LogOut = function () {
this.setAuth(null);
return true;
};
AuthService.prototype.setAuth = function (auth) {
if (auth) {
localStorage.setItem(this.authKey, JSON.stringify(auth));
}
else {
localStorage.removeItem(this.authKey);
}
return true;
};
AuthService.prototype.getAuth = function () {
var i = localStorage.getItem(this.authKey);
return i === null ? null : JSON.parse(i);
};
AuthService.prototype.isLoggedIn = function () {
return localStorage.getItem(this.authKey) !== null ? true : false;
};
return AuthService;
}());
var aa = new AuthService();
var gettoken = aa.getAuth();
if (gettoken !== null) {
token = gettoken.token;
}
</script>
To add token to the header of each anchor tag put below script also to
your main layout.
<script>
var links = $('a');
for (var i = 0; i < links.length; i++) {
links[i].onclick = function check() {
addheader(this.href);
return false;
}
}
function addheader(object) {
let xhr = new XMLHttpRequest();
xhr.open("GET", object, true);
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
xhr.send(null);
xhr.onload = function () {
window.history.pushState("/", "", xhr.responseURL);
//mycontainer is a div for parialview content
$("#mycontainer").html(xhr.responseText);
window.onpopstate = function (e) {
if (e.state) {
$("html").html = e.state;
document.title = e.state.pageTitle;
}
};
};
}
</script>
Remember that using of this approach, each view has to be loaded as a partial view.
If you insert url address in a web browser bar directly this solution doesn't work. I haven't figured it out yet. That's why to manage token authentication is better using single page application, not multipage application.
You can use this boilerplate to understand how to implement JWT tokenization with .Net Core. In the project you can find JWT, Swagger and EF features.

HttpClient returns nothing even if the request is successfull

I am trying to call an MVC Controller action from an API Controller (both in different applications), I can successfully make a call to the API Controller and returns the result but the controll never gets back to the calling method and PostMan shows the request still pending.
I have this method in my WebApi Controller
[HttpGet]
public BaseModel GetUserId(string email)
{
if (string.IsNullOrWhiteSpace(email))
{
return new BaseModel
{
success = false,
message = "invalid username or email."
};
}
var result = _security.GetUserId(email);
var baseModel = JsonConvert.DeserializeObject<BaseModel>(result.Result);
return baseModel;
}
_security.GetUserById
public async Task<string> GetUserId(string userName)
{
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string,string>("email",userName)
});
var response = await httpClient.PostAsync(baseUri + "Account/GetUserId", content);
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().Result;
return result;
}
return "";
}
Here is My API Controller action
[HttpPost]
[AllowAnonymous]
public async Task<BaseModel> GetUserId(string email)
{
var user = await _userManager.FindByEmailAsync(email);
if (user == null)
{
return new BaseModel
{
success = false,
message = "No user exists with the specified email"
};
}
user = await _userManager.FindByNameAsync(email);
if (user == null)
{
return new BaseModel
{
success = false,
message = "No user exists with the specified username"
};
}
return new BaseModel
{
success = true,
data = user.Id
};
}

Resources