As it is mention in the MS doc you can authorize your SignalR with access token like this:
let connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub", {
accessTokenFactory: () => {
// Get and return the access token.
// This function can return a JavaScript Promise if asynchronous
// logic is required to retrieve the access token.
}
})
.build();
and you can use in your backend code (with IUserIdProvider) like this
public class EmailBasedUserIdProvider : IUserIdProvider
{
public virtual string GetUserId(HubConnectionContext connection)
{
return connection.User?.FindFirst(ClaimTypes.Email)?.Value!;
}
}
I don't have a proper token to pass to the accessTokenFactory, but I have UserId on my client and I want to use this userIs with GetUserId method, so I could distinguish who the chat belongs to by UserId instead of whole Token. Is it possible to pass another value (or just a one claim) to HubConnectionBuilder? Like for example:
let connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub", {
accessTokenFactory: () => {
// Pass your value or just a custom claim so it could be retrive on server side
}
})
.build();
Is it too late to answer this?
You can use any string as a token, so you can do:
let connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub", {
accessTokenFactory: () => {
return "this:is:my:token";
}
})
.build();
and then on your server you can have
public class CustomTokenSchemeHandler : AuthenticationHandler<CustomTokenSchemeOptions>
{
...
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
var messageReceivedContext = new MessageReceivedContext(Context, Scheme, Options);
var token = Context.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
if (token is null)
{
return AuthenticateResult.NoResult();
}
string[] userInfoArray = token.Split(":");
var claims = new[]
{
new Claim(ClaimTypes.Name, userInfoArray[1]),
new Claim(ClaimTypes.Sid, userInfoArray[0])
// add whatever else you want here
};
var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, Scheme.Name));
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return AuthenticateResult.Success(ticket);
}
...
}
and in your services configuration:
builder.Services.AddAuthentication("CustomToken")
.AddScheme<CustomTokenSchemeOptions, CustomTokenSchemeHandler>("CustomToken");
more or less. Some connecting elements/boilerplate code is probably missing but this should give you the general idea how to go about this.