Machine to Machine API Authorization with Identity Server 7

Thilina Shashimal Senarath
9 min readJun 18, 2024

--

Introduction

In recent years, APIs have become crucial to the digital strategies of modern enterprises. It’s essential to have appropriate access control management to securely distribute digital assets and maintain privacy. Consequently, API security has become a forefront issue for modern enterprises.

API security has long been acknowledged as a vital component of identity provider functionality, with nearly every IAM (Identity and Access Management) solution offering support for it.

WSO2 Identity Server enhances API security capabilities, and the recently released WSO2 Identity Server 7 introduces additional features for API security such as first-class support for defining API resources, Role-Based Access Control (RBAC) for API resources, and machine-to-machine (M2M) API authorization.

This article will explore machine-to-machine API authorization and how WSO2 Identity Server 7 facilitates this type of authorization.

What is Machine-to-Machine (M2M) communication?

Machine-to-machine (M2M) communication represents the autonomous exchange of data between machines, devices, or services. The term “machine” in machine to machine communication refers to any autonomous system that can send or receive information within a network. This autonomous system may be a server, IoT device, CLI tool, docker container.

M2M Authorization

The exchange of information between machines must always be secure to protect against unauthorized access. This necessity brings machine-to-machine (M2M) authentication and authorization to the forefront. Authentication confirms a machine’s identity, while authorization specifies the actions or resources the authenticated machine can access. Typically, trust in systems is established by authorizing a user. However, in M2M communication, where user involvement is absent, trust must be established by the client, which could be an application, agent, process, or autonomous system. In these scenarios, traditional authentication methods such as username,password or social logins are impractical.

So how are we going to fulfill this machine to machine authentication and authorization scenario? Client credential grant of the OAuth 2.0 protocol defines the steps that a machine must follow to securely access protected resources.

M2M Authorization using OAuth 2.0

The OAuth 2.0 Client Credentials grant type is ideal for securing interactions in machine-to-machine (M2M) applications, such as APIs, backend services, servers, background processes, or command line interfaces (CLIs) that don’t require human users.

The Client Credentials grant flow, as outlined in the OAuth 2.0 RFC 6749 standard, specifies the procedures that client applications must follow to access protected resources. In this grant type, the client possesses two key pieces of information: the client ID and the client secret. Using these credentials, the client can request an access token for protected resources. The Client Credentials grant should be used with clients that can securely maintain the client secret.

  1. The client sends a request to the authorization server with its client ID and client secret to authenticate itself.
  2. Upon successful authentication, the authorization server issues an access token to the client.
  3. The client then uses this access token to request access to the protected resources from the resource server. The token is typically included in the HTTP Authorization header.

Use Cases for M2M

  • IoT : Many companies are adopting IoT technology to enhance operational efficiency and create interconnected environments. In these settings, various IoT devices communicate with each other to perform tasks without human intervention. Each device must be authenticated to ensure secure data transmission and prevent unauthorized access, maintaining the integrity and confidentiality of the network.
  • Backend to Backend (Microservices) : Most companies are now moving toward microservices architecture to resolve their complex use cases. In this setup, when backend services communicate, the client service must be authenticated before it can access any resources from the other service.
  • CLI tools / Cron jobs : As businesses automate more of their operations, CLI tools and cron jobs become essential for executing scheduled tasks and automations. These tools require proper authentication to access necessary APIs and perform their functions securely. This ensures that only authorized scripts run critical tasks, preventing unauthorized access and potential security risks within the system.

Machine to Machine API Authorization with Identity Server 7

With the latest release, WSO2 Identity Server is now allowing API developers to represent API resources as first-class citizens within its brand-new console. Once an API is registered, developers can define and associate a set of permissions in the form of scopes. These API resources and associated scopes can then be used to define authorization policies, ensuring that authorization policies are evaluated before issuing an access token. WSO2 Identity Server has introduced a new application template for machine-to-machine (M2M) applications, allowing you to authorize api resources to access APIs.

Sample M2M Scenario

The academic institution’s portal features a course management console designed to enable students to browse and enroll in courses. Through this console, students have the ability to access a comprehensive list of available courses, examine the content of each, and proceed to enroll in their chosen courses.

These courses are created by the respective field lecturers. Lecturers can use the same management console to create courses. Lecturers create the course content and submit it for approval from the administration.

The administrative staff members review the course and its content, and if approved, they schedule the course for publication. The administration then publishes the course a week before it starts.

To streamline the publishing process, the administration has automated it by implementing a cronjob. The cronjob checks for any scheduled courses that are ready to be published every day. If there are any courses available, the cron job will publish them automatically.

Course Management API

We have created a sample backend API developed for managing courses, showcasing JWT authentication and scope-based access control. You can view the full source code and further details on GitHub.

JWT Authentication : JWT Authentication acts as the first gatekeeper in our API, validating user identities before they interact with the system. We verify the authenticity of tokens based on a secure key obtained from a JWKS.

import { expressjwt } from 'express-jwt';
import jwksRsa from 'jwks-rsa';

// JWT authentication middleware configuration
const jwtCheck = expressjwt({
secret: jwksRsa.expressJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: 'https://localhost:9444/oauth2/jwks'
}) as GetVerificationKey,
audience: 'MPydZFwuXfZfhdqHB_FnHRIjUKYa',
issuer: 'https://localhost:9444/oauth2/token',
algorithms: ['RS256']
});

Access Control via Scopes : Access control is enforced through scopes embedded within the JWT. These scopes determine what actions a user can perform within our API. Our custom middleware determineScopes will decide which scopes are need for particular endpoint and checkScope checks if the JWT includes the required scopes for accessing specific endpoints.

export const determineScopes = (req, res, next) => {

var requiredScope
if (req.path === '/api/courses') {
if (req.method === 'GET') {
const status = typeof req.query.status === 'string' ? req.query.status.toLowerCase() : 'published';
requiredScope = scopes[status] || 'courses:read-published';
}
else if (req.method === 'POST') {
requiredScope = 'courses:write';
}
}

...

req.requiredScope = requiredScope;
next();
}


const checkScope = (expectedScope: string) => (req, res, next) => {
if (!req.auth || !req.auth.scope || req.auth.scope.split(' ').indexOf(expectedScope) < 0) {
return next(new Error('Missing required scope: ' + expectedScope));
}
next();
};

For example, to access the endpoint for creating a course, the user must have the courses:write permission.

app.post('/api/courses', determineScopes, checkScope, async (req, res) => {
const newCourse = req.body;
// Validate input
if (!newCourse || !newCourse.name || !newCourse.details || !newCourse.started_date) {
return res.status(400).send('Invalid course data');
}
// Assign an id to the new course
newCourse.id = coursesDb.length + 1;
newCourse.pending = true;
newCourse.published = false;
// Add the new course to the database
coursesDb.push(newCourse);
// Return the new course
res.json(newCourse);
});

This approach ensures that our course management API remains both secure and compliant with defined access policies, providing fine-grained control over who can do what within the system.

WSO2 Identity Server Setup

We are going to use WSO2 Identity Server 7 to control access to our course management API. (Please ensure that this article focuses solely on M2M API authorization.)

Register API Resource :

First, we will register the API resource for our course management API in the Identity Server.

register course management API resource
add scopes
setting require authorization

Create M2M Application :

Then, we will create an M2M application that will be used by our scheduled job to obtain a token to access the course management API.

application templates
m2m application creation

Authorize M2M App to Consume API :

Currently, our M2M application does not have permissions to use the course management API. We must grant authorization to the application to use the course management API and its scopes.

authorize course management API to m2m app

All is completed, and now our scheduled job can use our M2M application to obtain a token with the required permissions to publish courses.

Automate Course Publishing By Scheduled Job

Since this article focuses solely on M2M API authorization, we will only explain the scheduled job, not the management portal.

The following script fetches approved courses from an API and publishes those starting within a week. It obtains an access token with the required permissions for course publication from an M2M application, checks for approved courses, and for each one, verifies if the start date is within the past week. If so, it publishes the course and outputs the result. If no valid token or courses are found, it exits with an error message.

#!/bin/bash

# Define API endpoints
tokenEndpoint="https://localhost:9443/oauth2/token"
getApprovedCoursesUrl="http://localhost:3000/api/courses?status=approved"

# Obtain an access token
response=$(curl -k -s -X POST $tokenEndpoint \
-d "grant_type=client_credentials" \
-d "client_id=<client_id>" \
-d "client_secret=<client_secret>" \
-d "scope=courses:read-approved courses:publish")
# Extract access token from response
accessToken=$(echo $response | jq -r '.access_token')
# Check if the access token was actually received
if [ -z "$accessToken" ] || [ "$accessToken" == "null" ]; then
echo "Failed to retrieve access token"
exit 1
fi

# Get approved courses
approvedCourses=$(curl -k -s -X GET $getApprovedCoursesUrl \
-H "Authorization:Bearer ${accessToken}")

# If approved courses were received, publish one by one
if [ -n "$approvedCourses" ] && [ "$approvedCourses" != "null" ]; then
for row in $(echo "${approvedCourses}" | jq -r '.[] | @base64'); do
_jq() {
echo ${row} | base64 --decode | jq -r ${1}
}
courseId=$(_jq '.id')
courseName=$(_jq '.name')
startDate=$(_jq '.started_date')

# Convert the start date to seconds
startSeconds=$(date -j -f "%Y-%m-%d" "${startDate}" "+%s")

# Get the current date in seconds
currentSeconds=$(date "+%s")

# Calculate the difference in weeks
diffWeeks=$(( ($startSeconds - $currentSeconds) / 604800 ))
echo $diffWeeks
if [ $diffWeeks -lt 1 ]; then
echo "Publishing course: $courseName"
# Publish the course
publishCourseUrl="http://localhost:3000/api/courses/$courseId"
publishResponse=$(curl -k -s -X PATCH $publishCourseUrl \
-H "Authorization:Bearer ${accessToken}" \
-H "Content-Type:application/json" \
-d '{"status":"published"}')
echo $publishResponse
# Check if the course was published successfully
if [ -n "$publishResponse" ] && [ "$publishResponse" != "null" ]; then
echo "Course published successfully"
else
echo "Failed to publish course"
fi
else
echo "Course start date is more than a week ago. Not publishing."
fi
done
else
echo "No approved courses found"
fi

Thank you for reading our exploration of machine-to-machine (M2M) API authorization using WSO2 Identity Server 7. As APIs continue to play a pivotal role in digital transformation, understanding and implementing robust M2M authorization mechanisms becomes essential. WSO2 Identity Server 7’s advancements offer valuable tools to meet these needs, helping organizations to safeguard their digital ecosystems effectively. We hope this guide aids in your efforts to enhance API security and encourage you to leverage these insights in your projects.

--

--

Thilina Shashimal Senarath

Undergraduate of Computer Science and Engineering in University of Moratuwa, Sri Lanka