-4

I'm trying to make an simple chat website for a school project. The frontend is vanilla JS and backend is ASP DOTNET 8. It is now that I have a lot of trouble with authorization. Login and register work fine but when I try to make an API call to search for a user to an controller with [authorize] I keep getting a 401. I know why I get a 401 because with the code below I check for a value in the token whoever there is nothing there.

My question is that I don't know how to fix it. I tried different things but nothing seems to work on why the JWT token isn't being send back so it can be authorize by the back-end.

options.Events = new JwtBearerEvents
{
    OnMessageReceived = context =>
    {
        // Log all cookies
        Console.WriteLine("=== OnMessageReceived ===");
        Console.WriteLine($"Cookies received: {string.Join(", ", context.Request.Cookies.Keys)}");

        // 1) SignalR websocket transports send access_token in query string
        var accessToken = context.Request.Query["access_token"].FirstOrDefault();
        if (!string.IsNullOrEmpty(accessToken))
        {
            Console.WriteLine(" Token found in query string");
            context.Token = accessToken;
            return Task.CompletedTask;
        }

        // 2) fallback to the AuthToken cookie
        if (context.Request.Cookies.TryGetValue("AuthToken", out var cookieToken) && !string.IsNullOrEmpty(cookieToken))
        {
            Console.WriteLine($" Token found in AuthToken cookie: {cookieToken.Substring(0, 20)}...");
            context.Token = cookieToken;
        }
        else
        {
            Console.WriteLine(" No AuthToken cookie found!");
        }

        return Task.CompletedTask;
    }
};

So the code below shows what the code in the front-end looks like and there also some code for SignalR but that works just fine for now it is primarily the search function for a user here is the code.

render() {
    const root = document.createElement('div');
    root.innerHTML = `
      <div style="display:flex; gap:12px;">
        <div style="width:260px;">
          <h3>Users</h3>
          <div><input id="search" placeholder="search"></div>
          <button id="searchBtn">Search</button>
          <div id="users" class="user-list"></div>
        </div>
        <div style="flex:1;">
          <h3>Chat <span id="chatWith">no one</span></h3>
          <div id="chatWindow" class="chat-window"></div>
          <textarea id="msg" rows="3" style="width:100%"></textarea>
          <div><button id="sendBtn">Send</button> <button id="refreshBtn">Refresh</button></div>
        </div>
      </div>
    `;
    root.querySelector('#searchBtn').addEventListener('click', async ()=> {
      const q = root.querySelector('#search').value;
      const res = await fetch(API + '/api/Users/search?q=' + encodeURIComponent(q), { withCredentials: true });
      const users = await res.json();
      const usersEl = root.querySelector('#users');
      usersEl.innerHTML = '';
      users.forEach(u=> {

I know it is not the nicest code to look at but after getting stuck here for a week that is the least of my priority so Ii know. Also here is the back-end code to where I make the call.

using ChatBackendFinal.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace ChatBackendFinal.Controllers
{
    [ApiController]
    [Route("api/Users")]
    [Authorize(Policy = "AuthenticatedUsersOnly")]
    public class UsersController : ControllerBase
    {
        private readonly IUserService _userService;
        public UsersController(IUserService userService)
        {
            _userService = userService;
        }
        [HttpGet("search")]
        public async Task<IActionResult> SearchUsers([FromQuery] string query)
        {
            var users = await _userService.SearchAsync(query);
            var result = users.Select(u => new { u.Id, u.Username, u.Email });
            return Ok(result);
        }
    }
}
New contributor
Tjeerd Evers is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
13
  • Did the browser accept the cookie when it was attempted to set it, can you see it in your dev tools? How exactly was it set, can you show us the Set-Cookie header received by the browser? Commented yesterday
  • is this what you mean? Name: AuthToken Value: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyIiwibmFtZWlkIjoiMiIsInVuaXF1ZV9uYW1lIjpbIkhhcnJ5IiwiSGFycnkiXSwiZW1haWwiOlsidGplZXJkLmplbWlyZXZlcnNAaG90bWFpbC5jb20iLCJ0amVlcmQuamVtaXJldmVyc0Bob3RtYWlsLmNvbSJdLCJyb2xlIjoiVXNlciIsIm5iZiI6MTc2NDI1NzY1MSwiZXhwIjoxNzY0MjY0ODUxLCJpYXQiOjE3NjQyNTc2NTF9.Qo1DT44Ghk4iOczjv7fRQ2qHU6F0ykjD6RjQbhV_ESk Domain: localhost Path: / Expires: 2025-11-28T15:34:11.780Z Size: 350 Httponly: checkmark SameSite: lax Priority: medium Commented yesterday
  • You are in a cross-origin scenario here, right? Assuming you are, if you're already setting withCredentials. But then the cookie must not be set with SameSite: lax, because that explicitly excludes it from being send with fetch requests, among other things, developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/… Commented yesterday
  • Yes i'm on cross-origin scenario. For now the SameSite is lax due to me being in develpoment but i was planning to set it to strict would that also affect it? Commented yesterday
  • Yes, strict would mean that no cookie will be send with cross-origin requests at all, no matter what type of request. Commented yesterday

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.