This content originally appeared on Level Up Coding - Medium and was authored by Kunal Nalawade
If you are building a web application, implementing APIs is a necessary requirement. The data you display to the user needs to be fetched from an API service that exists on a different server.
Sometimes, your website may need to restrict access to some of these APIs to prevent them from getting fetched anywhere else. The restrictions could be anything ranging from the availability of a user to the role of the user. This is referred to as authorization.
In this post, I am going to show you how to implement authorization with a frontend (React) and a backend (Node JS) using JSON Web Token (JWT). We will be implementing three API calls to demonstrate the process.
Authorization
In an application involving API services, security should be taken into consideration. The APIs should not be accessible from anywhere outside the application. Also, you also want to make sure the APIs are only accessible to the necessary entity. For this, you need to implement authorization. Consider the following two scenarios.
If your application involves authenticating users, you want to ensure that certain services can only be accessed by authenticated users. For example, on Amazon, anyone can view a list of available products, but a particular user’s orders, purchases, payment information, etc. should only be accessible to the authenticated user.
Another use case is where a service is accessible only to a certain user. On a school website, a student can view his/her grades but only a teacher is authorized to modify them.
When a user is authenticated, the authentication service sends an access token back to the application. The access token contains information about the user, his/her role, the time of login, and its expiration time along with other details.
While making an API request, an authorization header containing the access token is added. This token is decoded in the backend and information about the user is retrieved. Depending on the information, the API decides whether the user is authorized to get the response.
We are going to implement a similar scenario. I’ll cover authentication in a later post. Here, we’ll skip straight to the end of authentication i.e. obtaining the access token, and then use the same token to demonstrate three API calls.
We’ll be using JWT in this post.
What is JWT?
JWT is a secure way of sending information in an encoded form. The token contains three parts:
- Header: This part contains the token’s type and the algorithm used to encode the token.
- Payload: This part contains information about the user and other information such as token expiry.
- Signature: This part is used to sign the token and verify that the message was not changed when transferred.
A JWT looks like this with all the parts in encoded form:
[Header].[Payload].[Signature]
An example of JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Visit here to decode a JWT. Watch this video to learn more about the implementation of JWT in Node.js.
Now that you know a little bit about Authorization and JWT, let’s start the implementation.
Setting Up
React App
Create a folder authorization-frontend in your project directory. Inside it, run the following command to create the React app.
create-react-app authorization-frontend
We’ll use Bootstrap in this project, so add this CDN to index.html file.
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
Alternatively, you can download the bootstrap source files from here.
We’ll use the Axios library to make API calls. Install it using the command npm i axios.
Node.js Server
First, install Node.js if you don’t have it in your system. Download it from here.
Create a separate folder named api-server for server code. In that folder, run the command npm init and input values for the given prompts. It should create a package.json file in your folder. The file shows the modules you have installed in your project directory.
We are using the following modules:
- express: Node.js framework that makes it easy to build servers
- cors: Allows cross-origin sources to make API requests. Learn more.
- jsonwebtoken: To generate an access token
Install them with the command npm i express cors jsonwebtoken.
Now, create a file server.js that contains the necessary code to set up a node server. Include the following code:
const express = require('express')
const cors = require('cors')
const jwt = require('jsonwebtoken')
const app = express()
// For sending JSON data through POST requests
app.use(express.json());
app.use(cors({
origin: '*'
}))
// Define APIs here
const PORT = 8000
app.listen(PORT, () => {
console.log('Listening on port', PORT);
})
For this project, allow all sources under CORS i.e. any browser can access these APIs. But this is not a good practice while developing an actual application.
Get the access token
Now that you have set up both applications, it’s time to generate the access token in the backend and pass it to the frontend i.e. implement a dummy authentication.
We’ll generate two types of access tokens: one for a normal user and another for an admin user.
Endpoint for fetching the token
Create an API endpoint for fetching the token. Use a POST API since we are getting a request body from the frontend that normally contains the user’s credentials during authentication. In our case, the frontend only sends a value indicating the type of token to fetch.
app.post('/access_token', (req, res) => {
const { value } = req.body;
switch(value) {
case 1:
// generate normal token
case 2:
// generate admin token
default:
// Send error message
}
})
Generate an access token
Let’s have two user objects, a normal and an admin user. Also, define a secret which will be used to sign the token.
const NORMAL_USER = {
name: 'kunal',
admin: false
}
const ADMIN_USER = {
name: 'alex',
admin: true
}
const SECRET = 'client-secret'
Note: Defining a secret inside your application code is not a good practice, you should have it in an env file.
The token can be generated by using the sign() function.
jwt.sign(NORMAL_USER, SECRET, (err, token) => {
res.json({ accessToken: token })
})
For admin token, replace NORMAL_USER with ADMIN_USER
Now, let’s check by decoding the token. The iat field represents the time at which the token was issued.
Fetch the token
On the frontend side, import the Axios library and initialize the hostname of the backend server.
import axios from 'axios'
const HOST_NAME = 'http://localhost:8000'
Then, create two buttons for fetching a normal token and an admin token respectively.
On clicking the buttons, the handleGetTokenClick() method is called that fetches the access token with an option parameter to determine which token to fetch.
function handleGetTokenClick(option) { }
Inside this method, make a post request to the API to the endpoint /access_token.
axios.post(HOST_NAME+'/access_token', { value: option })
.then(res => {
--- HANDLE THE RESPONSE ---
})
The response looks like this.
Store the token as state
Get the access token from the response and store it in session storage (or local storage; read about the difference here).
Create a state variable to hold the access token.
const [accessToken, setAccessToken] =
useState(sessionStorage.getItem('accessToken'));
Also, set the state when you receive the access token from the API. Following is the code for handling the response.
const { accessToken } = res.data;
sessionStorage.setItem('accessToken', accessToken);
setAccessToken(accessToken);
API calls
Now, it’s time to implement API calls. As mentioned before, we are going to make three GET API calls:
- Public API: accessible to anyone.
- Private API: accessible only to the authenticated user (i.e. with the access token)
- Restricted API: accessible only to the admin user.
Implement the three APIs
Public API
This API sends a simple response when called.
app.get('/public_api', (req, res) => {
res.send('Public API called')
})
Private API
This API expects an Authorization Header with a valid access token.
app.get('/private_api', (req, res) => { ... })
First, check if the user has sent an authorization header. If not, then send an error message with a 401 status code. This indicates a lack of credentials or invalid credentials.
const auth_header = req.headers.authorization;
if(!auth_header) res.send(401, 'Unauthorized request')
If the request has an authorization header, get the access token from it. Since the authorization header is of the form Bearer access_token, use the split() function to get the access token.
const accessToken = auth_header.split(' ')[1]
Now, use the verify() function to verify the token. It takes the token, the secret, and a callback function as parameters. If the token is valid, the callback function is called with the decoded payload else it is called with an error.
jwt.verify(accessToken, SECRET, (err, payload) => {
if (err) res.send(401, 'Unauthorized request')
res.send('Private API called')
})
Test the API using Postman.
Restricted API
This API can only be called by an admin user. The logic is almost similar to the private API except we also check if the user is an admin.
app.get('/restricted_api', (req, res) => {
const auth_header = req.headers.authorization;
if(!auth_header) res.send(401, 'Unauthorized request')
const accessToken = auth_header.split(' ')[1]
jwt.verify(accessToken, SECRET, (err, user) => {
if (err) res.send(401, 'Unauthorized request')
if (user.admin == true) res.send('Restricted API called')
res.send(401, 'Unauthorized request')
})
})
Now, if a normal user makes a request to this API, it sends a 401 error.
Create state to store the response
On the frontend side, create three state variables to store the response from each API.
const [publicResponse, setPublicResponse] = useState('')
const [privateResponse, setPrivateResponse] = useState('')
const [restrictedResponse, setRestrictedResponse] = useState('')
Create buttons to call APIs
On clicking each button, the handleAPIButtonClick() method is called that takes also takes an option parameter to decide which API to call.
Using switch-case statements call each API based on the option passed.
Call the APIs
Call the public API.
axios.get(HOST_NAME + '/public_api').then(res => {
setPublicResponse(res.data)
})
While calling the private API, pass the authorization header in the form Bearer access_token. Read more about Bearer tokens here.
Also, implement the catch block to handle the error response.
axios.get(HOST_NAME + '/private_api', {
headers: {
Authorization: 'Bearer ' + accessToken
}
}).then(res => {
setPrivateResponse(res.data)
}).catch(err => {
setPrivateResponse(err.response.data)
})
Call the restricted API in a similar way, but replace the endpoint and the state update function.
Wrapping up
Consider the above APIs as a template for your own implementation. If you have a page that displays user info, implement the private API. Information that can only be visible to certain users comes under restricted API.
You can add any type of restrictions to your APIs. All you have to do is pass the access token, decode it and check if the user satisfies those restrictions.
I have not added the HTML and CSS code in this post as I only wanted to focus on the logical part. You can find the implementation on GitHub.
Comment down below if you find anything incorrect or know a better implementation.
Conclusion
Authorization helps make your APIs secure and restricted. The use of JWT makes it easy to implement authorization. In this post, I have shown you how to generate an access token and use it to access different types of APIs. This post is a simple demonstration of how authorization can be implemented in your application.
I have explained each and every step in simple words to help you understand authorization. I hope this helps in your future projects.
If you are unable to understand the content or find the explanation unsatisfactory, comment your thoughts below. New ideas are always appreciated! Give a few claps if you liked this post. Subscribe and follow me for weekly content. Reach out to me on Twitter if you want to discuss anything. Till then, Goodbye!
Level Up Coding
Thanks for being a part of our community! More content in the Level Up Coding publication.
Follow: Twitter, LinkedIn, Newsletter
Level Up is transforming tech recruiting ➡️ Join our talent collective
How to implement authorization in your application using JWT was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Level Up Coding - Medium and was authored by Kunal Nalawade
Kunal Nalawade | Sciencx (2022-06-26T12:34:37+00:00) How to implement authorization in your application using JWT. Retrieved from https://www.scien.cx/2022/06/26/how-to-implement-authorization-in-your-application-using-jwt/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.