locked
How to handle external authentication when OWIN middleware and client are different hosts? RRS feed

  • Question

  • User809845054 posted

    Hi,

    I'm trying to develop WEB API for mobile and regular site with some common functionality, one of which is authentication service. I take server side part of VS2013 SPA template and trying to implement security based on individual accounts. The main requirement is ability to login with username/password and login via facebook. Tempate for VS2013 works fine when OWIN middleware and client - in the same project (like in example with VS2013 SPA), but when it's not there some revision should be made which I want to share:

    1. On WEB API which serves as OWIN middleware CORS should be enabled.
    2. In UI client (which is separate project/solution) for each AJAX request should be added additional header "X-Requested-With": "XMLHttpRequest". I noticed that without it WEB API returns XML and not JSON payload which cause incorrect mappings in UI samples (failJSON can't parse error messages).
    3. UI examples in VS2013 SPA template set for using with the same host, so some prefix with base url (WEB API url) should be added for each request in UI client.

    So I have successfully extended solution by implementing custom UserManager, UserStore, IIdentityValidator and IPasswordHasher which works with my existing MongoDB database and custom logic. Username/password authentication works just fine - I receive bearer token from WEB API and can use it in subsequent calls. But the main problem I have with external authentication: in my case with facebook. Actually all external login flow goes well and predicted till last step which is:

    The authorization endpoint checks the external sign in cookie principal and finds the associated application user, then signs in the user as Bearer authentication type into the authorization server middleware. Since the authorization server sees that the request parameter response_type is token (in step 1), it will trigger implicit flow, which will create access the token and append it to the redirect_uri (step 1) as URL fragment. For example:
    HTTP/1.1 302 Found
    Cache-Control: no-cache
    Pragma: no-cache
    Expires: -1
    Location: /#access_token=asd2342SDIUKJdsfjk3234&token_type=bearer&expires_in=1200&state=06hwltIjvnTn44hc
    Set-Cookie: .AspNet.External=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT
    Set-Cookie: .AspNet.Cookies=WJgdyZQs9N8TG20EWnik-j0; path=/; HttpOnly
    Content-Length: 0

    Here you can see /#access_token which is generated for WEB API host, full url looks like:

    http://mobileapi.example.loc:61707/#access_token=zn73ihR7Uve3TNfTWNnB..AHHwOQijdOaeMDDccUIBbhPiEOVsGn2A&token_type=bearer&expires_in=1209600&state=jZbC35_Inoi8Zop22Mg7xyAzV-BUdE3Zj2k0bMcG5F81

    So it redirects not to client which initiated authentication (for example http://localhost:2108), but on middleware host itself (http://mobileapi.example.loc:61707 in my case). Definitely it gives 404 Not Found because WEB API contains only server-side and can't parse this #access_token - UI client should do it.

    So my question is how to correctly intercept redirection and substitute server host to client host?

    P.S. I found source code which builds this #access_token string. It is in ApplyResponseGrantAsync method of OAuthAuthorizationServerHandler class, which instance created from OAuthAuthorizationServerMiddleware. And it has internal accessability. So it to change this behaviour I should rewrite as well whole middleware which is not very good approach I think.

    P.S.S. Anoter option I see is to create global handler on WEB API which intercepts all incoming requests and if it find one which starts from #access_token, than it takes refferer host from request and redirects to it. But it's ugly.

    Thanx in advance.

    Friday, March 28, 2014 8:42 AM

All replies