API - Authentication and authorization

By their very nature, REST apis are stateless so whenever a request is received you need to make sure that the client making the request is who they say they are and that they are allowed to make the request.

There are 2 steps to this process,

  • step 1 is authentication, where the identify of the client is verified
  • step 2 is authorization, which is performed after a successful authentication, where policies and rules determine whether access is allowed

Authentication


HTTP Bearer Authentication is currently supported which requires the HTTP Authorization header to be sent with every request.

The form of the Authorization header is

Authorization: <type> <credentials>

If authentication fails then a 401 Unauthorized response is returned to the client.

HTTP Basic Authentication


Not supported.

HTTP Bearer Authentication


In HTTP Bearer Authentication, <type> is "Bearer" and <credentials> is an access token that has been provided to the client that will allow access to the protected resource.

For example,

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1ODY1OTQ1MTgsImlzcyI6IlNlcnZlclRlc3QiLCJqdGkiOiJxdmRpeGI4b2gzZTFoN3piNTFtMHF2bzhnc2s2aTB5cnR1emFwd2s3OWNmZ2Q1MnBuNGE0bHljbG53eHIzanV0IiwibWVtYmVyRW50aXR5SWRlbnRpZmllciI6Im82cTJpcyIsIm9yZ2FuaXNhdGlvbkVudGl0eUlkZW50aWZpZXIiOiJtN2w5aHciLCJzY29wZSI6Im9yZ2FuaXNhdGlvbiIsInNlY3JldFR5cGUiOiJkeW5hbWljIn0.VgjO_x5T77974WwY_qikH6bpMScM99Nxcu7DasIBjF0

The access token is usually only valid for a short time period, say 1 hour, and once the access token expires the client can maintain their access by using a refresh token to generate a new access token. This refresh token usually lasts for a longer time period, say 7 days. Once both the access token and refresh token have expired then client will need to get a new access token (see "How does a client get an access token" below).

The access token will be a JSON Web Token or JWT. The JWT is an encoded string comprised of 3 sections, separated by dots, header.payload.signature. The header and payload are JSON representations of data containing relevant information. The signature is used to verify the authenticity of the token using a secret known only to the api server.

If you load the access token eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1ODY1OTQ1MTgsImlzcyI6IlNlcnZlclRlc3QiLCJqdGkiOiJxdmRpeGI4b2gzZTFoN3piNTFtMHF2bzhnc2s2aTB5cnR1emFwd2s3OWNmZ2Q1MnBuNGE0bHljbG53eHIzanV0IiwibWVtYmVyRW50aXR5SWRlbnRpZmllciI6Im82cTJpcyIsIm9yZ2FuaXNhdGlvbkVudGl0eUlkZW50aWZpZXIiOiJtN2w5aHciLCJzY29wZSI6Im9yZ2FuaXNhdGlvbiIsInNlY3JldFR5cGUiOiJkeW5hbWljIn0.VgjO_x5T77974WwY_qikH6bpMScM99Nxcu7DasIBjF0
into jwt.io, you will see the following for header and payload.
{
"typ": "JWT",
"alg": "HS256"
}

{
"iat": 1586594518,
"iss": "ServerTest",
"jti": "qvdixb8oh3e1h7zb51m0qvo8gsk6i0yrtuzapwk79cfgd52pn4a4lyclnwxr3jut",
"memberEntityId": "2549",
"memberEntityIdentifier": "o6q2is",
"organisationEntityIdentifier": "m7l9hw",
"scope": "architect",
"secretType": "dynamic"
}

exp = expiry time
iat = issued at time
iss = issuer
jti = unique identifier

Note that this example does not have an expiry time.

Note that the token contains details of the authenticated memberEntity and organisationEntity.

For scope, see section on "Authorization".

For secretType see section on "Secrets".

When the api server processes the request, the first thing it does is to extract the header and payload from the given access token and re-create the token signature. If this matches the signature on the given access token then the access token has not been tampered with and can be accepted as valid.

If verification is successful then a MemberEntityModel will be instantiated from the memberEntityIdentifier taken from the token. Note that there is no need to do a DB lookup to verify the credentials of the client.

Secrets

The tokens used by api.methodgrid.com will have a fixed secret.

Fixed

Tokens that are destined for use by application clients will use a built-in fixed secret. The application client will usually present a set of valid credentials via a login screen to acquire a token. Such tokens will be short lived and will naturally expire when they reach their expiry time unless the client takes steps to prolong access by such means as re-presenting valid credentials.

How does a client get an access token


Method 1.

This method is used when the client is able to provide sign in credentials. For example, a web application.

Make a POST request to https://api.methodgrid.com/v1/authenticate and pass email, password and domain (if applicable) in the request body.

The credentials will be verified and if valid, a response with status 200 OK containing a JWT access token will be returned.

This access token will have an expiry time of 1 hour and will include the memberEntityIdentifier. As discussed earlier, this access token will use a fixed secret.

The client should save the access token and include it in each request to the api.

Authorization

Only paid accounts will be authorized to make api requests.

If using HTTP Bearer Authentication, a "scope" attribute will be expected in the access token.

Initially, at least, the "scope" will be equivalent to an application role, that is, "architect", "builder" and "user". Api requests can be constrained to a particular scope via middleware and the relevant scope must be supplied in the access token for authorization to be successful. Each route is thus responsible for checking that the correct scope or scopes has been supplied.

Scope values could even be more granular and allow authorization to be managed at the resource or route level. For example, scope=grids authorizes the user full authorization to delete, get, post and put grids resources. Whereas, scope=getGrids only authorizes the user to get grids resources.