Authentication

All requests must be signed by the client.

Authentication Scheme

Sample Request:

GET /rest/directory/uin/000000000/json/ HTTP/1.1
Date: Tue, 04 May 2010 20:46:36 GMT
Authorization: TAM faa36ed8ef1a:4iRRBxwPuKD71JYYn7192Zuopkr3mPQ/HcQAfbSM2mQ=

Required Headers

Each request made by your client must provide, at a minimum, the Date and Authorization headers.

Date Header

The Date header should be provided in GMT, using a valid HTTP date format. The date in your request will be used to verify that the request is current. If you cannot set the date header for your request, you should instead set the x-tam-date header using the same format:

GET /rest/directory/uin/000000000/json/ HTTP/1.1
x-tam-date: Tue, 04 May 2010 20:46:36 GMT
Authorization: TAM faa36ed8ef1a:4iRRBxwPuKD71JYYn7192Zuopkr3mPQ/HcQAfbSM2mQ=

Authorization Header

The Authorization header will have the following form:

Authorization: TAM identifier:signature

The identifier is specific to your client. The signature is a HMAC-SHA256 of an authentication string made up of the request URI, the date, and your client’s identifier.

The following pseudo-code illustrates how to build the signature:

Authorization = "TAM" + " " + identifier + ":" + signature;
signature = Base64( HMAC-SHA256( UTF-8-Encoding-Of( shared_secret, authentication_string ) ) );

authentication_string = request_uri + "\n" +
    date + "\n" +
    identifier;

The date should be exactly what is provided in the Date header. The request URI is the path of the endpoint.

Sample Code (Python)

import base64
import hmac
import hashlib
import requests

from datetime import datetime, tzinfo, timedelta

class GMT(tzinfo):
    def dst(self, dt):
        d = datetime(dt.year, 4, 1)
        self.dston = d - timedelta(days=d.weekday() + 1)
        d = datetime(dt.year, 11, 1)
        self.dstoff = d - timedelta(days=d.weekday() + 1)
        if self.dston <= dt.replace(tzinfo=None) < self.dstoff:
            return timedelta(hours=1)
        else:
            return timedelta(0)
    def utcoffset(self, dt):
        return timedelta(hours=0)
    def tzname(self, dt):
        return "GMT"
        
def get_date():
    gmt = GMT()
    return datetime.now(tz=gmt).strftime('%a, %d %b %Y %H:%M:%S GMT')

def get_headers(auth_string):
    dig = hmac.new(bytes('SECRET_KEY', 'latin-1'),
                   msg=bytes(auth_string, 'latin-1'),
                   digestmod=hashlib.sha256).digest()
    signature = base64.b64encode(dig).decode('utf-8')
    headers = {'Date': str(get_date()),
               'Authorization': 'TAM ' + 'CLIENT_ID' + ':' + signature}
    return headers

# https://mqs.tamu.edu/rest/docs/

def data_from_netid(uin):
    url = 'https://mqs.tamu.edu/rest/directory/uin/%s/json/' % (uin,)
    auth_string = '/rest/directory/uin/%s/json/\n%s\n%s' % \
                                            (uin,
                                             str(get_date()),
                                             'CLIENT_ID',)
    try:
        response = requests.get(url, headers=get_headers(auth_string))
        data = response.json()
        return data
    except:
        print('Error getting uin from API: %s' % (uin))
        return response


print(data_from_netid("UIN"))