graphql-platform
graphql-platform copied to clipboard
Strawberry Shake WebSocket configuration doesn't have Options field to configure authorization header
Is there an existing issue for this?
- [X] I have searched the existing issues
Product
Strawberry Shake
Describe the bug
In the Authentication section of the documentation si described that, in order to configure the authentication header for WebSockets, I can use the SetRequestHeader() method under Options
services
.AddConferenceClient()
.ConfigureWebSocketClient(client =>
{
client.Uri = new Uri("ws://localhost:" + port + "/graphql");
client.Socket.Options.SetRequestHeader("Authorization", "Bearer ...");
});
But under client.Socket
there is no Options
field.
Steps to reproduce
- Create a sample .NET 7 Console project.
- Import the
StrawberryShake.Server
and theMicrosoft.Extensions.Hosting
NuGet packages. - Follow the get started guide until
ConferenceClient
is created - Try to setup the headers in
Program.cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) => {
services.AddConferenceClient()
.ConfigureWebSocketClient(client => {
client.Socket.Options.SetRequestHeader("Authorization", "Bearer ...");
});
})
.Build();
host.Run();
Relevant log output
No response
Additional Context?
No response
Version
13.0.5
@fuji97 Have you found a wait to send the auth token? I tried ISocketConnectionInterceptor, but it is called after the connect call.
@TheJemy191 I fixed it by using the following custom ISocketConnectionInterceptor
public class WebApiSocketRequestInterceptor : ISocketConnectionInterceptor {
private readonly IAccessTokenProvider _accessTokenProvider;
private readonly IConfiguration _configuration;
private readonly ILogger<WebApiSocketRequestInterceptor> _logger;
public WebApiSocketRequestInterceptor(IAccessTokenProvider accessTokenProvider, IConfiguration configuration, ILogger<WebApiSocketRequestInterceptor> logger) {
_accessTokenProvider = accessTokenProvider;
_configuration = configuration;
_logger = logger;
}
public async ValueTask<object?> CreateConnectionInitPayload(ISocketProtocol protocol, CancellationToken cancellationToken) {
try {
var scopes = _configuration.GetSection("Scopes:Admin").Get<string[]>();
var accessTokenResult = await _accessTokenProvider.RequestAccessToken(new AccessTokenRequestOptions() {
Scopes = scopes
});
if (!accessTokenResult.TryGetToken(out var token)) {
throw new InvalidOperationException("Could not get access token.");
}
return new Dictionary<string, string> { ["authToken"] = token.Value };
}
catch (Exception e) {
_logger.LogError(e, "Error while creating connection init payload");
throw;
}
}
}
And it the Program.cs
:
builder.Services.AddTransient<WebApiSocketRequestInterceptor>();
/// Other code
builder.Services.AddGraphQLClient()
.ConfigureHttpClient((services, client) => {
client.BaseAddress = new Uri(url);
}, b => b.AddHttpMessageHandler<WebApiAuthorizationMessageHandler>())
.ConfigureWebSocketClient((services, client) => {
var logger = services.GetRequiredService<ILogger<Program>>();
try {
var interceptor = services.CreateScope().ServiceProvider.GetRequiredService<WebApiSocketRequestInterceptor>();
client.Uri = new Uri(url);
client.ConnectionInterceptor = interceptor;
}
catch (Exception e) {
logger.LogError(e, "Error while creating connection init payload");
throw;
}
services.CreateScope().ServiceProvider.GetRequiredService<WebApiSocketRequestInterceptor>();
});
This is directly copied from my Blazor WASM project, so you should change the settings to works with yours (i.e. scopes and the token provider) but for the rest it should works. Let me know if it works
That won't work. Event with your change WebApiSocketRequestInterceptor is called after the first connection and the server never receive any token.
Found the problem. I needed to add .AddSocketSessionInterceptor<SocketAuthorizationInterceptor>()
when configuring HotChocolate. This is what receive the initial payload from ISocketConnectionInterceptor
You need to put the token on the init request ....
The authorization header is not supported in browser when using websocket.
I will post how to do it later.
@TheJemy191 exactly ... on the server you need SocketAuthorizationInterceptor
we used to have a full demo ... but we need to have another look at that.
The workaround above does not seem to be able to add headers. How can that be done?
(Our API, including the WS endpoint, requires a session ID in a cookie, with an Authorization
header available for simpler smoke testing, and it's the Authorization
header I want to add now.)