Colin's Journal

Colin's Journal: A place for thoughts about politics, software, and daily life.

October 4th, 2015

HTTP Push Notfications

 

Arran Beach

Arran Beach

Owlauth allows users to register a device (e.g. a phone) and then use this device to confirm their identify when logging into a website or application.  For this to work the Owlauth app running on the phone needs to be able to receive push notifications of authentication requests.  There are many centralised ways to push notifications to a phone, but as each domain owner can run their own Owlauth server, a centralised solution isn’t a good fit.

By taking advantage of Go’s cheap handling of concurrent processing with Goroutines, a simple HTTP based push approach can be used.  Clients connect to the server:

  1. Passing a Bearer token that authorizes them as a registered device.
  2. Passing an If-None-Match ETag if it has one.
  3. The HTTP GET then blocks until either:
    1. The HTTP Keep Alive timeout is approaching – in which case the server returns nothing.
    2. A new authentication request is available or an existing request goes away.
  4. When the GET returns, an ETag header reflecting the current state.
  5. The client loops, issuing a new HTTP GET request with the latest ETag.

The server returns before the Keep Alive timeout, which means that the client will reuse the same TCP (and SSL) session as for the first request.  This makes this timeout and GET operation an effective ping that proves the connection is still established.  If the TCP connection becomes invalid, the client’s HTTP library will open a new connection to the server, giving the desired reconnect behaviour.

The server implementation in Go is straightforward:

        var requestedEtag string
        requestedEtag = r.Header.Get("If-None-Match")

        authChannel := reqStore.RegisterListener(dev.DeviceOwner)
        defer reqStore.UnregisterListener(dev.DeviceOwner, authChannel)
        clientGone := w.(http.CloseNotifier).CloseNotify()
        var request *reqdb.PendingRequests
        timeout := time.NewTimer(DeviceRequestGetTimeout)

        for {
            select {
            case req := <-authChannel:
                if req.GetEtag() != requestedEtag {
                    request = &req
                    // Return the ETag
                    w.Header().Add("ETag", req.GetEtag())
                    return request, nil
                }
                // Just loop and try again.
            case <-clientGone:
                // Nothing to be done - just return
                log.Printf("Device gone - returning\n")
                w.Header().Add("ETag", requestedEtag)
                return nil, nil
            case <-timeout.C:
                log.Printf("Device request get timeout reached.\n")
                w.Header().Add("ETag", requestedEtag)
                return nil, nil
            }
        }

The reqStore object keeps track of outstanding authorisation requests and provides the details on a channel to all registered clients that are sat waiting in this GET.

The only other element of the equation on the client side is adopting a suitable retry strategy when http connections are not working.  For desktops that could be just a simple back-off to a few seconds sleep.  For the Android client it needs to taken into account the current network state to avoid excessive battery drain.

I’ve now got a basic version of this working on my phone.  I’ll run it for a while and see how much battery impact it has.

September 8th, 2015

Killing Passwords

Passwords on websites and in apps are the bane of internet usage.  Much has been written (recently in TechCrunch – Kill The Password) on how painful they are to generate and remember.  Password managers help with the challenge, but are  a cumbersome band aid.

When building a website application, adding username and passwords is also painful, requiring extensive work to get working well and securely.  So, what are the alternatives?  There are some good ideas out there, but they tend to be complicated (OpenID Connect), or put large identity providers in a special position (Fido, OpenID Connect) or are centralized and cost money (e.g. Clef).

I think it’s possible to build a simple, distributed, secure authentication mechanism that allows users to login to sites without generating passwords.  The vision is that a user can authenticate themselves easily:

  • Enter your email address
  • See a pass phrase in the application / website
  • Check your phone – if the same pass phrase is displayed, tap authenticate and you are in

I’ve been experimenting with how this could be done, documenting the specification on an Owlauth Github page, and writing an authentication server in Go that implements the specification.  It’s not done yet – the current code sends email to the user with a link rather than a notification to a phone – but it’s close enough that it proves it can work.

In addition to the specification, I’ve also got a test application running (A larder app for tracking food best before dates) that authenticates using this method.

The challenge now is how to move this forward.  Finishing the implementation to allow device based authentication is straightforward (I’ve got most of the code done), but it’s of no use if there isn’t a community of developers interested in deploying it.

Copyright 2015 Colin Stewart

Email: colin at owlfish.com