cloud-gov / hhs-acf-uc-api

API for the Dept. of Health and Human Services: Administration for Children and Families' Unaccompanied Children database
Creative Commons Zero v1.0 Universal
2 stars 1 forks source link

Add authentication to the API #21

Closed mgwalker closed 8 years ago

mgwalker commented 8 years ago

Adds JWT-based authentication to the API

Changes

First, an authentication source must be defined (in our current setup, that source is the Dashboard). The authentication source and the API must agree on an HMAC secret, which is some string used as the key for the HMAC algorithm. (A couple of passwords from https://www.grc.com/passwords.htm concatenated together are a reasonable choice.)

The client either obtains or constructs a token with a payload (currently this payload is arbitrary, but it should include an exp expiration claim for security reasons) signed by secret key. It then adds an Authorization header to all requests to the API: Authorization: Token [token]. Any API calls lacking that header will result in an HTTP status 401.

The API will attempt to decode the token and then verify the signature using the authentication secret. The signature is expected to be HMAC with 512-bit SHA. While the algorithm is indicated in the token header, that is ignored for security purposes, so both the authentication source and all clients using the tokens must agree on the algorithm. If the token cannot be decoded or the signature is invalid, the API will return an HTTP status 401.

Once the token is decoded, the expiration date is verified. If the token is invalid for any reason or expired, the API returns an HTTP status 401. Otherwise the controller handling the route will do its thing.

Generating Tokens

require 'JWT'

secret = "my-hmac-secret"
token = JWT.encode({:role => 'admin', :exp => Time.now.to_i + 86400}, secret, "HS512")

token will be a string containing a JWT token. Note this token will expire in 24 hours - the exp claim is the Unix timestamp of the expiration date. The API relies on the JWT gem to validate expirations using the standard exp claim.

mgwalker commented 8 years ago

All Rails and Ruby feedback welcome! Needs tests, which I will start working on separate from this (yay another new thing to learn!) - just wanted to get something useable as quickly as possible.

Some more possible future needs: