4

My JavaScript SignalR client routinely connects to my asp.net core implementation of IdentityServer4.

On the client I see:

Information: WebSocket connected to wss://localhost:5001/signal/satellite?
idsrv.session=4ec93d2f4c3b9a970ff82a537ae04d97&id=0eUBg2-xobp4CNttuIQJcg

But, it also doesn't connect much of the time, with an error that there was an unexpected token in JSON at position 0.

It seems like it runs well for a bit and then poorly, even if I re-login, it still throws the error. In the browser, the call always looks more or less like:

https://localhost:5001/signal/satellite?
idsrv.session=89364018a975e4fefff9ad0869b1ae09

I don't seem to need the middleware for it to move the querystring value into the header, I still get the user in my hub during onConnect with their sub claim, etc. However, if I do put in the middleware before app.UseAuthentication() and watch for:

context.Request.QueryString.Value

when it successfully handshakes with the server, I see:

idsrv.session=89364018a975e4fefff9ad0869b1ae09

but when it doesn't, I see this:

?client_id=internal&redirect_uri=https%3A%2F%2Flocalhost%3A5001%2Fsignin-oidc&response_type=code%20id_token&scope=openid%20profile%20offline_access%20Harvey&response_mode=form_post&nonce=636817245670169226.ZWM2OWQ0ZWEtOTQzMC00YTJlLWI4MzQtYmIxZDZjOWVlYjg5ZTA4NTU2M2QtNjczZi00MTlmLThjYmQtZWUzZTQ1ODMzNDQ0&state=CfDJ8MCxOjJiJLdKqZrnPwOHDhqMnzWz6MqRb03SxToClqQ1F3n9g8yLdW683HRpZSHd-5wkN-6je4tHJkA8sc5i6YoKRxtMHwnWqxVW5-nXFaaH0TfOLUeqfxDzXLxnftmWFXLjK3Y7b6R2WzcDLEjChU1_Fk6X64SAHNRqeizGDPzRhxpV0U5w19Bbt7pUyRbYymn2WNedCS1F7g_wtwtJXDjCzWKBxqvPZ5Dtg99gxKkANalKYs7C4-fm7YdD0gFvsuV4CXsu0T06MjzID_zpA_F7TmSue4vGI-0_qY55Swc5mbLWUwKHtj6ZTfOG4UmTEP_hbj2PO9w2oNg9TWqTPtDC3-qSl1fTUkY0EtCwbA7F&x-client-SKU=ID_NETSTANDARD1_4&x-client-ver=5.2.0.0

so I'm stuck either not needing to do it because it succeeds on its own or the querystring never makes it to the middleware to move over (which is probably why it can't do it on its own)

What am I missing for it to consistently work?

Add Hybrid Client to IdentityServer4:

        new Client
        {
            ClientId = "mvc",
            ClientName = "MVC Client",
            AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,

            ClientSecrets = 
            {
                new Secret("secret".Sha256())
            },

            RedirectUris = { "http://localhost:5002/signin-oidc" },
            PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },

            AllowedScopes = 
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile,
                "api1"
            },
            AllowOfflineAccess = true
        }

and then in startup on the mvc client:

 ServiceCollection.AddAuthentication(options =>
            {
                options.DefaultScheme = "Cookies";
                options.DefaultChallengeScheme = "oidc";
            })
            .AddCookie("Cookies")
            .AddOpenIdConnect("oidc", options =>
            {
                options.SignInScheme = "Cookies";

                options.Authority = "https://localhost:5001";
                options.RequireHttpsMetadata = false;
                options.ClientSecret = "secret";
                options.ClientId = "mvc";

                options.ResponseType = "code id_token";
                options.SaveTokens = true;
                options.GetClaimsFromUserInfoEndpoint = true;

                options.Scope.Add("offline_access");
                options.Scope.Add("api1");
                options.ClaimActions.MapJsonKey("website", "website"); 
            });

This is modeled after the example: Quickstart5_HybridAndApi

In SignalR on server:

        [Authorize]
        public class SignalRSignalHub : Hub
        {
            public override Task OnConnectedAsync()
            {
                var context = Context.GetHttpContext();
                return base.OnConnectedAsync();
            }
        }

SignalR JavaScript Client:

    self.signalRConnection = new signalR.HubConnectionBuilder()
.withUrl("/signal/satellite?" + document.cookie).build();
ScottFoster1000
  • 488
  • 1
  • 6
  • 20
  • 1
    Could it be that the access token expired? Do you renew the access token somewhere? Take a look at he question and answer here for more information: https://stackoverflow.com/questions/54498454/still-logged-in-mvc-site-but-cant-call-web-api/54507122#54507122 – Ruard van Elburg Feb 07 '19 at 13:17
  • 1
    My API calls are still working fine, it's just the websocket calls. The websocket has a url it's handshaking on and I do get the auth/login page if I follow the url in the browser, but I can't auth, during this time the api and mvc controller calls are still working. I'm transferring the cookie idsrv through the querystring like the docs suggest, but when it's failing auth, it's never getting to the middleware where I can move the querystring token anywhere. When the authentication is working through the socket, I don't need to transfer the idsrv value in the middleware. – ScottFoster1000 Feb 07 '19 at 19:40
  • BTW - thanks, the way I wrote it, does make it sound like it could be the same issue, but I have experiences where right after I auth, I get the error on the websocket while the api and view controller calls work and then if I restart the dev environment, the websocket and the api/views work off and on. – ScottFoster1000 Feb 11 '19 at 06:50
  • 1
    I have no experience with SignalR yet, so I can only mention some probable causes but can't really help you. There is another support channel. You may want to ask your question there: https://gitter.im/IdentityServer/IdentityServer4 – Ruard van Elburg Feb 11 '19 at 07:00

0 Answers0