In this article, We will learn about how to secure Magento 2 API.
We will generate tokens to access Magento 2 API. Magento 2 provides three types of API Authentication.
- Token based authentication
- OAUTH based authentication
- Session Based Authentication
1). Token based authentication
To make a web API call from a client such as a Magento 2 mobile application, you must supply an access token.
Request for Token
Magento 2 provides a separate token service for administrators and customers. When you request a token from one of these services, the service returns a unique access token in exchange for an account’s username and password.
Request for Customer Token
Customer token : /V1/integration/customer/token

Request for Admin Token
Admin Token : /V1/integration/admin/token

Authentication
Magento 2 allow developers to define web API resources and their permissions in the webapi.xml
configuration file.
Before you can make web API calls, you must authenticate your identity and have the necessary permissions (authorization) to access the API resource. Authentication allows the application to identify the caller’s user type. A user’s (administrator, integration, customer, or guest) access rights determine an API call’s resource accessibility.
USER TYPE | ACCESSIBLE RESOURCES (DEFINED IN WEBAPI.XML) |
Administrator or Integration | if administrators are authorized for the Magento_Customer::group resource, they can make a GET /V1/customerGroups/:id call. |
Customer | Resources with anonymous or self permission |
Guest user | Resources with anonymous permission |
Example for self
The user authenticates him/herself by username & password then token will be generated in response that token act as self permission for further processes.
<route url="/V1/customers" method="GET"> <service class="Vendor\Module\Api\CustomerManagementInterface" method="getCustomerList"/> <resources> <resource ref="self"/> </resources> <data> <parameter name="customer_id" force="true">%customer_id%</parameter> </data> </route>
Example for anonymous
Web APIs to be accessed by unauthenticated users.
<route url="/V1/products" method="GET"><br> <service class="Venodor\Module\Api\ProductRepositoryInterface" method="getProducts"/><br> <resources><br> <resource ref="anonymous"/><br> </resources><br></route>
Example for admin authorized REST API
Custom web API in Magento 2
<route url="/V1/products" method="GET"> <service class="Venodor\Module\Api\ProductRepositoryInterface" method="getProducts"/> <resources> <resource ref="Vendor_Module::name"/> </resources> </route>
Create custom module ACl in etc/acl.xml
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd"> <acl> <resources> <resource id="Magento_Backend::admin"> <resource id="Vendor_Module::name" title="Pruduct List"/> </resource> </resources> </acl> </config>
2). OAuth-based authentication
OAuth authentication with Adobe Commerce and Magento Open Source is based on OAuth 1.0a, an open standard for secure API authentication. OAuth is a token-passing mechanism that allows a system to control which third-party applications have access to internal data without revealing or storing any user IDs or passwords.
In Commerce, a third-party application that uses OAuth for authentication is called integration. An integration defines which resources the application can access. The application can be granted access to all resources or a customized subset of resources.
As the process of registering the integration proceeds, Commerce creates the tokens that the application needs for authentication. It first creates a request token. This token is short-lived and must be exchanged for an access token. Access tokens are long-lived and will not expire unless the merchant revokes access from the application.
OAuth authentication process
The following diagram shows the OAuth authentication process. Each step is described further.

1). Create an integration:- The merchant creates an integration from Admin. Commerce generates a consumer key and a consumer secret.
2). Activate the integration:- The OAuth process begins when the merchant activates the integration. Magento sends the OAuth consumer key and secret, an OAuth verifier, and the store URL to the external application via HTTPS post to the page defined in the Callback Link field in Admin. See Activate an integration for more information.
3). Process activation information:- The integrator must store the activation information received in step 2. These parameters will be used to ask for tokens.
4). Call the application’s login page:- Commerce calls the page defined in the Identity Link field in Admin.
5). Merchant logs in to the external application:- If the login is successful, the application returns to the location specified in the call. The login page is dismissed.
6). Ask for a request token:- The application uses the POST /oauth/token/request
REST API to ask for a request token. The Authorization
header includes the consumer key and other information. See Get a request token for details about this token request.
7). Send the request token:- Commerce returns a request token and request token secret.
8). Ask for an access token:- The application uses the POST /oauth/token/access
REST API to ask for an access token. The Authorization
header includes the request token and other information. See Get an access token for details about this token request.
9). Commerce sends the access token:- If this request is successful, Magento returns an access token and access token secret.
10). The application can access Magento resources:- All requests sent to Commerce must use the full set of request parameters in Authorization
header. See Access the web APIs for more information.
Activate an integration
The integration must be configured from the Admin (System > Extensions > Integrations). The configuration includes a callback URL and an identity link URL. The callback URL specifies where OAuth credentials can be sent when using OAuth for token exchange. The identity link points to the login page of the third-party application that is integrating with Commerce.

A merchant can choose to select Save and Activate when the integration is created. Alternatively, the merchant can click on Activate against a previously saved integration from the Integration grid.
When the integration is created, Commerce generates a consumer key and a consumer secret.
Activating the integration submits the credentials to the endpoint specified when creating the Integration. An HTTP POST from Commerce to the Integration endpoint will contain these attributes:
- store_base_url
oauth_verifier
oauth_consumer_key
oauth_consumer_secret
Integrations use the oauth_consumer_key
key to get a request token and the oauth_verifier
to get an access token.
OAuth handshake details
The process of completing the OAuth handshake requires that you,
- Get a request token
- Get an access token
Get a request token
A request token is a temporary token that the user exchanges for an access token. Use the following API to get a request token from Commerce:
POST /oauth/token/request
You must include these request parameters in the Authorization
header in the call:
PARAMETER | DESCRIPTION |
oauth_consumer_key | The consumer key is generated when you create the integration. |
oauth_signature_method | The name of the signature method used to sign the request. Must be the value HMAC-SHA256 . |
oauth_signature | A generated value (signature) |
oauth_nonce | A random value that is uniquely generated by the application. |
oauth_timestamp | A positive integer, expressed in the number of seconds since January 1, 1970 00:00:00 GMT. |
oauth_version | The OAuth version. |
The response contains these fields:
1). oauth_token
:- The token to be used when requesting an access token.
2). oauth_token_secret:- A secret value that establishes ownership of the token.
The response looks like this:
oauth_token=4cqw0r7vo0s5goyyqnjb72sqj3vxwr0h&oauth_token_secret=rig3x3j5a9z5j6d4ubjwyf9f1l21itrr
Get an access token
The request token must be exchanged for an access token. Use the following API to get an access token from Commerce:
POST /oauth/token/access
You must include these request parameters in the Authorization
header in the call:
This process is known as a 2-legged OAuth handshake.
PARAMETER | DESCRIPTION |
oauth_consumer_key | The consumer key value that you retrieve after you register the integration. |
oauth_nonce | A random value that is uniquely generated by the application. |
oauth_signature | A generated value (signature) |
oauth_signature_method | The name of the signature method used to sign the request. Must be the value HMAC-SHA256 . |
oauth_timestamp | A positive integer, expressed in the number of seconds since January 1, 1970 00:00:00 GMT. |
oauth_version | The OAuth version. |
oauth_token | The oauth_token value, or request token, obtained in Get a request token. |
oauth_verifier | The verification code that is tied to the consumer and request token. It is sent as part of the initial POST operation when the integration is activated. |
The response looks like this:
oauth_token=0lnuajnuzeei2o8xcddii5us77xnb6v0&oauth_token_secret=1c6d2hycnir5ygf39fycs6zhtaagx8pd
Access the web APIs
After the integration is authorized to make API calls, third-party applications (registered as integrations) can invoke web APIs by using the access token.
To use the access token to make web API calls:
GET /rest/V1/products/1
You must include these request parameters in the Authorization
request header in the call:
- oauth_consumer_key
- oauth_nonce
- oauth_signature_method
- oauth_signature
- oauth_timestamp
- oauth_token
The OAuth signature
All OAuth handshake requests and Web Api requests include the signature as part of Authorization header. Its generated as follows:
You concatenate a set of URL-encoded attributes and parameters to construct the signature base string.
- HTTP method
- URL
- oauth_nonce
- oauth_signature_method
- oauth_timestamp
- oauth_version
- oauth_consumer_key
- oauth_token
You must use the HMAC-SHA256 signature method. The signing key is the concatenated values of the consumer secret and token secret separated by the ampersand character (ASCII code 38), even if empty. You must use parameter encoding to encode each value.
OAuth token exchange example
The scripts provided in this document simulate the Commerce OAuth 1.0a token exchange flow. You can drop these scripts under the document root directory of your installation so that they can be exposed as endpoints that your system can interact with to mimic the token exchange.
OAuth 1.0a token exchange step:
1). Login to your Admin and navigate to System > Extensions > Integrations
2). Click on Add New Integration.
3). Complete all details in the Integration Info tab
- Name : SomeUniqueIntegrationName
- Callback URL : http://your_app_host/endpoint.php
- Identity link URL : http://your_app_host/login.php
- Add permissions as desired on the API tab
4). Select the Save and Activate option from the drop down menu.
5). A pop-up window displays, confirming API permissions. Click Allow. (Make sure your browser allows pop-up windows.) The credentials are posted to endpoint.php. You should also see another pop-up for the identity linking step that opens the script from login.php.
6). Click Login. (There is no actual login check since this is a simulation.). The checklogin.php
script is called. It uses the posted credentials to complete the token exchange.
7). When the token exchange completes successfully, the user is redirected back to the Integrations grid. The newly-created integration should be in the Active state.
8). Click on the edit icon of the integration and check the Integration Details on the Integration Info tab. It should show all the credentials that can be used to make an authenticated API request using OAuth 1.0.
checklogin.php
<?php require './vendor/autoload.php'; $consumerKey = $_REQUEST['oauth_consumer_key']; $callback = $_REQUEST['callback_url']; session_id('test'); session_start(); /** Use $consumerKey to retrieve the following data in case it was stored in DB when received at "endpoint.php" */ if ($consumerKey !== $_SESSION['oauth_consumer_key']) { throw new \Exception("Consumer keys received on different requests do not match."); } $consumerSecret = $_SESSION['oauth_consumer_secret']; $magentoBaseUrl = rtrim($_SESSION['store_base_url'], '/'); $oauthVerifier = $_SESSION['oauth_verifier']; define('TESTS_BASE_URL', $magentoBaseUrl); $credentials = new \OAuth\Common\Consumer\Credentials($consumerKey, $consumerSecret, $magentoBaseUrl); $oAuthClient = new OauthClient($credentials); $requestToken = $oAuthClient->requestRequestToken(); $accessToken = $oAuthClient->requestAccessToken( $requestToken->getRequestToken(), $oauthVerifier, $requestToken->getRequestTokenSecret() ); header("location: $callback");
endpoint.php
<?php session_id('test'); session_start(); // If this data is stored in the DB, oauth_consumer_key can be used as ID to retrieve this data later in "checklogin.php" // For simplicity of this sample, it is stored in session $_SESSION['oauth_consumer_key'] = $_POST['oauth_consumer_key']; $_SESSION['oauth_consumer_secret'] = $_POST['oauth_consumer_secret']; $_SESSION['store_base_url'] = $_POST['store_base_url']; $_SESSION['oauth_verifier'] = $_POST['oauth_verifier']; session_write_close(); header("HTTP/1.0 200 OK"); echo "Response";
login.php
<?php $consumerKey = $_REQUEST['oauth_consumer_key']; $callbackUrl = urlencode(urldecode($_REQUEST['success_call_back'])); echo <<<HTML <table width="300" border="0" align="center" cellpadding="0" cellspacing="1" bgcolor="#CCCCCC"> <tr> <form name="form1" method="post" action="checklogin.php?oauth_consumer_key={$consumerKey}&callback_url={$callbackUrl}"> <td> <table width="100%" border="0" cellpadding="3" cellspacing="1" bgcolor="#FFFFFF"> <tr> <td colspan="3"><strong>Integrations Login</strong></td> </tr> <tr> <td width="78">Username</td> <td width="6">:</td> <td width="294"><input name="myusername" type="text" id="myusername"></td> </tr> <tr> <td>Password</td> <td>:</td> <td><input name="mypassword" type="text" id="mypassword"></td> </tr> <tr> <td> </td> <td> </td> <td><input type="submit" name="Submit" value="Login"></td> </tr> </table> </td> </form> </tr> </table> HTML;
OauthClient.php
<?php use OAuth\Common\Consumer\Credentials; use OAuth\Common\Http\Client\ClientInterface; use OAuth\Common\Http\Exception\TokenResponseException; use OAuth\Common\Http\Uri\Uri; use OAuth\Common\Http\Uri\UriInterface; use OAuth\Common\Storage\TokenStorageInterface; use OAuth\OAuth1\Service\AbstractService; use OAuth\OAuth1\Signature\SignatureInterface; use OAuth\OAuth1\Token\StdOAuth1Token; use OAuth\OAuth1\Token\TokenInterface; class OauthClient extends AbstractService { /** @var string|null */ protected $_oauthVerifier = null; public function __construct( Credentials $credentials, ClientInterface $httpClient = null, TokenStorageInterface $storage = null, SignatureInterface $signature = null, UriInterface $baseApiUri = null ) { if (!isset($httpClient)) { $httpClient = new \OAuth\Common\Http\Client\StreamClient(); } if (!isset($storage)) { $storage = new \OAuth\Common\Storage\Session(); } if (!isset($signature)) { $signature = new \OAuth\OAuth1\Signature\Signature($credentials); } parent::__construct($credentials, $httpClient, $storage, $signature, $baseApiUri); } /** * @return UriInterface */ public function getRequestTokenEndpoint() { return new Uri('http://my.host/oauth/token/request'); } /** * Returns the authorization API endpoint. * * @throws \OAuth\Common\Exception\Exception */ public function getAuthorizationEndpoint() { throw new \OAuth\Common\Exception\Exception( 'The REST API is 2-legged. Current operation is not available.' ); } /** * Returns the access token API endpoint. * * @return UriInterface */ public function getAccessTokenEndpoint() { return new Uri('http://magento.host/oauth/token/access'); } /** * Parses the access token response and returns a TokenInterface. * * @param string $responseBody * @return TokenInterface */ protected function parseAccessTokenResponse($responseBody) { return $this->_parseToken($responseBody); } /** * Parses the request token response and returns a TokenInterface. * * @param string $responseBody * @return TokenInterface * @throws TokenResponseException */ protected function parseRequestTokenResponse($responseBody) { $data = $this->_parseResponseBody($responseBody); if (isset($data['oauth_verifier'])) { $this->_oauthVerifier = $data['oauth_verifier']; } return $this->_parseToken($responseBody); } /** * Parse response body and create oAuth token object based on parameters provided. * * @param string $responseBody * @return StdOAuth1Token * @throws TokenResponseException */ protected function _parseToken($responseBody) { $data = $this->_parseResponseBody($responseBody); $token = new StdOAuth1Token(); $token->setRequestToken($data['oauth_token']); $token->setRequestTokenSecret($data['oauth_token_secret']); $token->setAccessToken($data['oauth_token']); $token->setAccessTokenSecret($data['oauth_token_secret']); $token->setEndOfLife(StdOAuth1Token::EOL_NEVER_EXPIRES); unset($data['oauth_token'], $data['oauth_token_secret']); $token->setExtraParams($data); return $token; } /** * Parse response body and return data in array. * * @param string $responseBody * @return array * @throws \OAuth\Common\Http\Exception\TokenResponseException */ protected function _parseResponseBody($responseBody) { if (!is_string($responseBody)) { throw new TokenResponseException("Response body is expected to be a string."); } parse_str($responseBody, $data); if (null === $data || !is_array($data)) { throw new TokenResponseException('Unable to parse response.'); } elseif (isset($data['error'])) { throw new TokenResponseException("Error occurred: '{$data['error']}'"); } return $data; } /** * @override to fix since parent implementation from lib not sending the oauth_verifier when requesting access token * Builds the authorization header for an authenticated API request * * @param string $method * @param UriInterface $uri the uri the request is headed * @param \OAuth\OAuth1\Token\TokenInterface $token * @param $bodyParams array * @return string */ protected function buildAuthorizationHeaderForAPIRequest( $method, UriInterface $uri, TokenInterface $token, $bodyParams = null ) { $this->signature->setTokenSecret($token->getAccessTokenSecret()); $parameters = $this->getBasicAuthorizationHeaderInfo(); if (isset($parameters['oauth_callback'])) { unset($parameters['oauth_callback']); } $parameters = array_merge($parameters, ['oauth_token' => $token->getAccessToken()]); $parameters = array_merge($parameters, $bodyParams); $parameters['oauth_signature'] = $this->signature->getSignature($uri, $parameters, $method); $authorizationHeader = 'OAuth '; $delimiter = ''; foreach ($parameters as $key => $value) { $authorizationHeader .= $delimiter . rawurlencode($key) . '="' . rawurlencode($value) . '"'; $delimiter = ', '; } return $authorizationHeader; } }
3). Session-based authentication
As a customer, you log in to the storefront with your customer credentials. As an admin, you log in to the Admin with your admin credentials.
The web API framework uses your logged-in session information to verify your identity and authorize access to the requested resource.
Customers can access resources that are configured with anonymous
or self
permission in the webapi.xml
configuration file.
Admins can access resources that are assigned to their Admin profile.
For example, if a customer is logged in to the storefront and the JavaScript widget invokes the self
API, details for the logged-in customer are fetched:
GET /rest/V1/customers/me
if an admin is logged in to the Admin and the JavaScript widget invokes the Magento_Customer::group
API, details for the logged-in admin are fetched. The web API framework establishes the identity of the admin user based on logged-in session information and authorizes access to the Magento_Customer::group
resource.
Admin session-based authentication is not currently possible for API endpoints.
The session based authentication functionality is restricted to AJAX calls. Direct browser requests cannot be made due to security vulnerabilities.
Hope this will help you.
Thanks 🙂
Be the first to comment.