Skip to content

Latest commit

 

History

History
92 lines (75 loc) · 2.83 KB

apidoc.md

File metadata and controls

92 lines (75 loc) · 2.83 KB

Authentication

The API uses a digital signature for authentication that is appended to the URL as a query string.

The following CoffeeScript code implements the signature process:

# Encode without ':' and strip milliseconds, since they are irrelevant.
toISOStringUrlsafe = (date) -> date.toISOString().replace(/:|\.[^Z]*/g, '')

NogAuth.signRequest = (key, req) ->
  authalgorithm = 'nog-v1'
  authkeyid = key.keyid
  now = new Date()
  authdate = toISOStringUrlsafe(now)
  authexpires = config.defaultExpires
  authnonce = crypto.randomBytes(10).toString('hex')
  if urlparse(req.url).query?
    req.url += '&'
  else
    req.url += '?'
  req.url += "authalgorithm=#{authalgorithm}"
  req.url += '&' + "authkeyid=#{authkeyid}"
  req.url += '&' + "authdate=#{authdate}"
  req.url += '&' + "authexpires=#{authexpires}"
  req.url += '&' + "authnonce=#{authnonce}"

  stringToSign = req.method + "\n" + req.url + "\n"
  hmac = crypto.createHmac 'sha256', key.secretkey
  hmac.update stringToSign
  authsignature = hmac.digest 'hex'

  req.url += '&' + "authsignature=#{authsignature}"

The method and the whole URL path are signed. The authsignature must be appended as the last query parameter.

authexpires is specified in seconds.

The authnonce is optional. If it is present, the request will be accepted only once. The authnonce needs to be unique only per authdate, so a small nonce is usually sufficient.

sign-req, available from the nog-starter-pack, can be used to sign requests for curl:

Example:

export NOG_KEYID=<copied>
export NOG_SECRETKEY=<copied>

curl $(
  ./tools/bin/sign-req GET \
  http://localhost:3000/api/blobs/31968d2e8b58e29e63851cb4b340216026f11f69
) | python -m json.tool

The following code implements the signature process in Python:

def sign_req(method, url):
    authkeyid = os.environ['NOG_KEYID']
    secretkey = os.environ['NOG_SECRETKEY'].encode()
    authalgorithm = 'nog-v1'
    authdate = datetime.utcnow().strftime('%Y-%m-%dT%H%M%SZ')
    authexpires = '600'
    authnonce = binascii.hexlify(os.urandom(5))

    parsed = urlparse(url)
    if parsed.query == '':
        path = parsed.path
        suffix = '?'
    else:
        path = parsed.path + '?' + parsed.query
        suffix = '&'
    suffix = suffix + 'authalgorithm=' + authalgorithm
    suffix = suffix + '&authkeyid=' + authkeyid
    suffix = suffix + '&authdate=' + authdate
    suffix = suffix + '&authexpires=' + authexpires
    suffix = suffix + '&authnonce=' + authnonce

    stringToSign = (method + '\n' + path + suffix + '\n').encode()
    authsignature = hexlify(hmac.new(
            secretkey, stringToSign, digestmod=hashlib.sha256
        ).digest()).decode()
    suffix = suffix + '&authsignature=' + authsignature
    return url + suffix