locked
No Bearer token in Request Headers RRS feed

  • Question

  • User-401080925 posted

    using Blazor 3.2 I need to automatically send the security token in request header,I don't use Identity,I have custom tables on the server for users,I get the token from login controller and save it to local storage

    public class JWTAuthenticationStateProvider : AuthenticationStateProvider, ILoginService
        {
            private readonly IJSRuntime js;
            private readonly HttpClient httpClient;
            private readonly string TOKENKEY = "TOKENKEY";
            private AuthenticationState Anonymous => new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
    
            public JWTAuthenticationStateProvider(IJSRuntime js, HttpClient httpClient)
            {
                this.js = js;
                this.httpClient = httpClient;
            }
            public override async Task<AuthenticationState> GetAuthenticationStateAsync()
            {
                var token = await js.GetFromLocalStorage(TOKENKEY);
                if (string.IsNullOrEmpty(token))
                {
                    return Anonymous;
                }
                return BuildAuthenticationState(token);
            }
    
            public AuthenticationState BuildAuthenticationState(string token)
            {
         
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
    
                return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(token), "jwt")));
            }
    
    
    
            public async Task Login(string token)
            {
                await js.SetInLocalStorage(TOKENKEY, token);
                var authState = BuildAuthenticationState(token);
                NotifyAuthenticationStateChanged(Task.FromResult(authState));
            }
    
            public async Task Logout()
            {
                await js.RemoveItem(TOKENKEY);
                httpClient.DefaultRequestHeaders.Authorization = null;
                NotifyAuthenticationStateChanged(Task.FromResult(Anonymous));
            }
        }
    

    for requests I use:

    public interface IHttpService
        {...
            Task<HttpResponseWrapper<object>> Post<T>(string url, T data);
          ...       
        }
        public class HttpService : IHttpService
        {
            private readonly HttpClient httpClient;
            private JsonSerializerOptions DefaultJsonSerializerOptions =>
                 new JsonSerializerOptions() { PropertyNameCaseInsensitive = true };
    
            public HttpService(HttpClient _httpClient)
            {
                httpClient = _httpClient;
            }
    
    
        .......   
    
            public async Task<HttpResponseWrapper<object>> Post<T>(string url, T data)
            {
                var dataJson = JsonSerializer.Serialize(data);
                var stringContent = new StringContent(dataJson, Encoding.UTF8, "application/json");
                var response = await httpClient.PostAsync(url, stringContent);
                return new HttpResponseWrapper<object>(null, response.IsSuccessStatusCode, response);
            }
    
    .........
    
    public class HttpResponseWrapper<T>
        { 
            public HttpResponseWrapper(T response, bool succes, HttpResponseMessage httpResponseMessage)
            {
                Response = response;
                Success = succes;
                HttpResponseMessage = httpResponseMessage;
            }
            public T Response { get; set; }
            public bool Success { get; set; }
            public HttpResponseMessage HttpResponseMessage { get; set; }
    
            public async Task<string> GetBody()
            {
                return await HttpResponseMessage.Content.ReadAsStringAsync();
            }
        }
    

    when I send a request to the server :

     var res = await httpService.Post<QueryObject, ResObject>($"{url}/get", query);
    

    I get 401(Unauthorized), in dev tools i see no Bearer token in Request

    Headers: :authority: localhost:44341 :method: POST :path: /api/datar/get :scheme: https accept: / accept-encoding: gzip, deflate, br accept-language: en-US,en;q=0.9 cache-control: no-cache content-length: 123 content-type: application/json; charset=utf-8 cookie: .AspNet.Consent=yes; .AspNetCore.Session=CfDJ8KV1S2nC4ehItE9KmaCETAilfhhNr%2BP3SQORWHzxbFYQLddeekAftj05md7N%2BWYjU1LxdcIBY4XW9muw13u2q2clwdsmQHLb2DqCKkQW%2FbcquzDPKYbcAtcuJEJ2OpOz75zgMYhRmL47zGhNvmhhHXbEEKGnQwpAk8gnAe6bF6XC origin: https://localhost:44341 pragma: no-cache referer: https://localhost:44341/sch sec-fetch-dest: empty sec-fetch-mode: cors sec-fetch-site: same-origin user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.80 Safari/537.36 OPR/72.0.3815.148

    Thursday, October 22, 2020 9:19 AM

All replies

  • User475983607 posted

    Is the a Blazor Server application? 

    The code is very hard to follow.  There's no code that fetches the token from local storage.  Also, there seems to be a lot of JWT processing code that reinvents the wheel. 

    Thursday, October 22, 2020 12:50 PM
  • User-401080925 posted

    Hi

    it is a Blazor Client app,above I put most of the code that is needed for token,does't the next line adding the token automatically on all  httpClient requests? 

     httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

    the fetching of the local token could be GetAuthenticationStateAsync from JWTAuthenticationStateProvider :

     public class JWTAuthenticationStateProvider : AuthenticationStateProvider, ILoginService
        {
            private readonly IJSRuntime js;
            private readonly HttpClient httpClient;
            private readonly string TOKENKEY = "TOKENKEY";
            private AuthenticationState Anonymous => new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
    
            public JWTAuthenticationStateProvider(IJSRuntime js, HttpClient httpClient)
            {
                this.js = js;
                this.httpClient = httpClient;
            }
            public override async Task<AuthenticationState> GetAuthenticationStateAsync()
            {
                var token = await js.GetFromLocalStorage(TOKENKEY);
                if (string.IsNullOrEmpty(token))
                {
                    return Anonymous;
                }
                return BuildAuthenticationState(token);
            }

    Thursday, October 22, 2020 1:34 PM
  • User475983607 posted

    There are two types of Blazor applications; Server and WASM.   

    Still you have not shared any code that populates the bearer token.  Let me put this another way.  Your code will NOT work in Blazor Server or WASM.  

    Local storage is not available to service code in Blazor server.  The code is running on the server not the client.  

    A Blazor WASM application does not need local storage.  The code is running in web assembly.  A static variable to singleton pattern is a far better choice.

    Thursday, October 22, 2020 2:26 PM
  • User-401080925 posted

    Hi.I'm new to Blazor,this is my first post.I'm trying to migrate an app from Angular to Blazor,in my case WASM.

    I'm stuck on sending token in request headers,the above code it's all I have for token fetches

    my code is inspired from here

    EDIT: When I navigate to a component/route the  GetAuthenticationStateAsync(posted above) fires,so that seems to be the code that uses token from LOCAL storage

    thanks

    Thursday, October 22, 2020 4:41 PM
  • User475983607 posted

    I recommend contacting the owner if you need assistance with the code.   Otherwise take a look at the official documentation which covers OIDC and remote auth servers.

    https://docs.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/hosted-with-identity-server?view=aspnetcore-3.1&tabs=visual-studio

    https://docs.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/?view=aspnetcore-3.1

    Thursday, October 22, 2020 6:32 PM
  • User-401080925 posted

    I've debug my code, GetAuthenticationStateAsync is called autmatically just before any http request,so httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token) is called too with correct token value but is not present in header request ,what is strange: seems to wok if I put that line just inside HttpService class,service is registered services.AddScoped<IHttpService, HttpService>() 

    Friday, October 23, 2020 6:30 AM
  • User475983607 posted

    I've debug my code, GetAuthenticationStateAsync is called autmatically just before any http request,so httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token) is called too with correct token value but is not present in header request ,what is strange: seems to wok if I put that line just inside HttpService class,service is registered services.AddScoped<IHttpService, HttpService>() 

    If I understand your response, adding the bearer token to the HttpClient instance works as expected.  Your expectation the source downloaded from GIT to automatically add token.   I recommend contacting source code owner if you need assistance with the code or you found a bug.  

    Otherwise,  you can find proven and tested libraries by reading the links in my first post.  The second link has a lot of links to other resources.  this is one of them.

    https://docs.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/standalone-with-authentication-library?view=aspnetcore-3.1&tabs=visual-studio

    Friday, October 23, 2020 1:51 PM
  • User-401080925 posted

    I've fixed moving httpClient.DefaultRequestHeaders.Authorization= new AuthenticationHeaderValue("Bearer", token) from GetAuthenticationStateAsync() just before any request made by HttpService class

    i see the same as my old code in may examples from google,one is there

    thanks

    Friday, October 23, 2020 2:43 PM