June 02, 2020
by Charlotte Fereday
A few months ago I gave a talk at a Node Girls and Women of Security meetup to share a few things I have learned about authentication and authorisation since joining our Security Engineering team at Tes. You can see the video of this talk here.
This post summarises some of the key points made during the talk, alongside some sketch notes and code snippets from an example app.
Authentication and authorisation both relate to the concept of identity. Though the words are similar their meanings are different. Let’s explore how...
At the most basic level, we can say that authentication is the process of checking the identity of a user: are you who you say you are?
The most common place that authentication is used is the Login Page of an application. During login user entered credentials are checked against what we have stored in the database. This allows us to verify that we know and trust a user is who they say they are, via, for example, a username and a password.
Although the concept of authentication is straightforward, the technical process of its implementation is typically complex, because it’s absolutely vital to keep users’ data secure. For this reason, many companies opt to use a third party company, for example Google or Auth0, to handle the authentication process for them.
Some companies choose to implement authentication themselves. Here are a couple of golden rules if you go down this route.
Keeping secret data secure is vitally important for any company to protect their users and their reputation. We want to mitigate against the risk that even if a bad actor got access to a database, they would never get a plain text password. The safest strategy to prevent this is to not store the plain text password at all.
One solution is to hash passwords to carry out a ‘one way’ transformation which turns turns a plain text password into an unrecognisable string. We can use one way encryption to verify the password whilst making it very difficult for a bad actor to transform it to its original plain text value.
We can safely hash passwords by using well maintained and recognised open source libraries, such as bcrypt library. Here’s an example code snippet using the bcrypt library to hash a password before storing it, to keep user credentials safe.
One of the most common places for an attack on an application is the Login page. Injection or hijacking attacks can aim to make our code do something we did not tell it to do, by sending an instruction where we would expect some user-entered data or credentials.
Never trust the user input to safeguard applications, but rather always validate and transform data before using it.
Again a widely used open source validation library like Joi can help you easily create schemas and transform the data into safe objects.
After a user has been authenticated, we can move onto checking what resource they are authorised to access. It's important to control who-can-access-what to protect data, reputation and revenue.
We can use roles to indicate whether or not a user should have access to a resource. For instance, only an administrator should be able to access the admin page, or only a particular client has access to a specific endpoint.
Json Web Tokens (JWT) help to implement authorisation. JWT is an open standard that defines a way to securely transmit information between parties as a JSON object.
We can trust this information because it is digitally signed and verified by server-side code. It helps authorisation systems scale, to ensure only those authorised have access to particular resources, and protect private personal data.
A JWT is digitally signed with a secret or a public/private key pair that is only known to an application. This means an application can ensure that the JWT was signed from a trusted source (via said secret or corresponding public key) and prevents it from being secretly tampered with.
Here’s an example of using the jsonwebtoken library to sign a JWT where it is then added to a cookie.
Role data is included as part of the JWT, for instance in this example if the username is ‘admin’ then this user gets an ‘admin’ role. Clearly this management of roles is a hack for a toy project, in a real secure system there will be more sophisticated ways of managing admins.
Once we have a JWT, we can verify that the token is valid on our servers, and only trust it if the JWT hasn’t been tampered with or expired.
The jsonwebtoken library allows us to digitally verify a user or client and effectively manage whether they should have access to a particular resource.
Aside from learning more about authentication and authorisation, the aim of this blog is to show that as engineers we can learn a few good security practices and have access to many open source libraries to help us build more secure applications.
Writing secure code is absolutely critical for our users - you don’t need to be a security expert to get started.
If you’d like to learn more about some of the topics touched on here, I've listed below some articles that I found useful.