Home > OS >  HttpListener ignoring everything after # (hash) in request
HttpListener ignoring everything after # (hash) in request

Time:12-16

So I'm new to C# and I don't know if what I'm seeing is obvious and intended behavior or if there's some nuance to the objects I'm using. I'm trying to set up a server to handle a redirect for an oauth flow for a StackOverflow app. The redirected url constructed looks like localhost:8080/#access_token=12345.

I basically have the following set up as my simple server to handle the redirect request and save the access_token.

public class ImplicitFlowHttpServer
{
    public int Port = 8080;
    private HttpListener _listener;

    public void Start()
    {
        var prefix = $"http://*:8080/";
        _listener = new HttpListener();
        _listener.Prefixes.Add(prefix);
        _listener.Start();
        _listener.BeginGetContext(new AsyncCallback(ListenerCallback), _listener);
    }

    private async void ListenerCallback(IAsyncResult result)
    {
        if (_listener.IsListening)
        {
            string oauthCode;
            var context = _listener.EndGetContext(result);
            var request = context.Request;
            
            // code to send response, not relevant to my question
            HttpListenerResponse response = context.Response;
            byte[] page = Encoding.ASCII.GetBytes(
                "You can close this browser tab now.");

            response.ContentLength64 = page.Length;
            Stream output = response.OutputStream;
            output.Write(page, 0, page.Length);
            output.Close();

            //
            
            Console.WriteLine($"Should receive a request to localhost:8080/#access_token=<token>");
            Console.WriteLine($"How can I see the access_token?");
            Console.WriteLine($"request.Url: {request.Url}");
            Console.WriteLine($"request.Url.Fragment: {request.Url.Fragment}");
            Console.WriteLine($"request.RawUrl: {request.RawUrl}");
            Console.WriteLine($"request.Url.AbsoluteUri: {request.Url.AbsoluteUri}");
            Console.WriteLine($"request.Url.OriginalString: {request.Url.OriginalString}");

            // <here is code to parse the access_token if it existed>
            // <here is code to stop the server>
        }
    }
}

You can see I'm expecting the hash somewhere in that request object, that the #access_token would exist and I just have to figure out how to get it out, but I think it's just cleaned out altogether. It doesn't have to do with the redirect, as I have the same problem if I spin up the server and then do curl "localhost:8080/?q=123&hello=world\#access_token=123456" With the above code I'll see

request.Url: http://localhost:8080/?q=123&hello=world\
request.Url.Fragment:
request.RawUrl: /?q=123&hello=world\
request.Url.AbsoluteUri: http://localhost:8080/?q=123&hello=world\
request.Url.OriginalString: http://localhost:8080/?q=123&hello=world\

So given that I'm stuck with this access token "in the hash", how am I supposed to get the access_token from that redirect?

CodePudding user response:

Fragment part of url (thing after the #) is special in that it's only for client-side use. The agent (web browser, curl etc) will remove fragment part from url when sending request to server. So it works as expected.

This is also the reason why token is passed this way in this oauth flow - so that when redirect happens, the token is not accessible to server, only to client.

As for how to solve this in your case, note how documentation at your link states:

The explicit flow should be used by server-side applications, with special care taken to never leak client_secret. Client side applications should use the implicit flow.

You are using implicit flow. If you would use explicit flow then token would be accessible to your server.

  •  Tags:  
  • c#
  • Related