Magento 2 API Authentication: Token, OAuth, Session Authentication

In Magento, developers are allowed to define web API resources and their permissions in a configuration file which is webapi.xml.

Before web API calls can be made, you have to authenticate your identity and obtain all the necessary permissions also called authorization to access the API resource. With authentication, Magento will be able to identify the user type of caller. And based on the user’s access rights, the resource accessibility of API calls is determined.

Besides, the resources list that you can access will depend on your user type. Because all customers have the same permissions, the same resources accessible. The preceding statement is also correct with guest users. A unique set of permissions that are configured in the Magento Admin can be provided to each administrator or integration user. All the permissions which are required to access particular resource are configured in the webapi.xml file. The below table will list all the resources that can be accessed by each user type:

User type Accessible resources
Administrator or Integration Resources for which administrators or integrators are authorized.
Customer Resources which have anonymous or self permission
Guest user Resources which have anonymous permission

In today post, I’m going to provide you the basic information about three Magento 2 API Authentications which are Token, OAuth and Session Authentication.

Magento 2 API Authentication

Token authentication

In order to make a web API call from a client, for example, mobile application, an access token need to be supplied on the call. The token acts as an electronic key which allows you to access the API.

The table below describes all the types of access tokens which Magento issues:

Token type Description Default lifetime
Integration The merchant will determine the Magento resources that the integration can access. Until it is manually revoked.
Admin The merchant will determine the Magento resources that an admin user can access. 4 hours
Customer Resources with anonymous or self permission are accessible. These settings cannot be edited by Merchants. 1 hour

Integration tokens

When integration is created and activated, a consumer key, consumer secret, access token, and access token secret are generated by Magento. However, the token-based authentication only requires the access token.

To generate an access token, following the below steps:

  • Step 1: Firstly, log in to your Admin, then go to System > Extensions > Integrations to open the Integrations page.
  • Step 2: Next, to display the New Integration page, click Add New Integration
  • Step 3: In the Name field, enter a unique name for the integration. Then, in the Your Password field, enter your admin password. With the remaining fields, you can leave it blanks.
  • Step 4: Click the API tab. And choose the Magento resources which the integration can access. You are allowed to choose all resources or a custom list.
  • Step 5: To save your changes and return to the Integrations page, click on the Save button.
  • Step 6: In the next step, click on the Activate link in the grid which corresponds to the integration that has just been created.
  • Step 7: Finally, click on the Allow button. After you have clicked the button, a dialog which is similar to the following one will be displayed.

!

You can use the access token in all calls which is made on behalf of the integration.

Admin and customer access tokens

A separate token service is provided for both administrators and customers by Magento. When a token is requested from one of these services, a unique access token will be returned in exchange for the username and password for a Magento account.

Guest user are allowed to access resources which are configured with the anonymous permission level. The framework of these users can not authenticate via existing authentication mechanisms. A guest user can specify a token in a web API call for a resource with anonymous permission.

Here are some calls that can be used to get an authentication token:

Request REST SOAP
Get admin token POST /V1/integration/admin/token integrationAdminTokenServiceV1
Get customer token POST /V1/integration/customer/token integrationCustomerTokenServiceV1

With the majority of web API calls, to prove your identity, this token is supplied in the Authorization request header with the Bearer HTTP authorization scheme. By default, 4 hours is the valid time of an admin token, while a customer token is only valid for 1 hour. These values can be changed by choosing Stores > Settings > Configuration > Services > OAuth > Access Token Expiration.

All the tokens which are expired will be removed by a cron job that runs on an hourly basis.

Request a token

An access token request includes three elements:

Component Specifies
Endpoint It is a combination of the server which meets the request, the service, and the resource against. For instance, in the endpoint: POST <host>/rest/<store_code>/V1/integration/customer/token. magento.host/index.php/ is the server, rest is the web service, /V1/integration/customer/token is the resource
Content type It is the content type of the request body. You can set this value to Content-Type:application/json or Content-Type:application/xml.
Credentials The username and password for an account on Magento. For these credentials to be specified in a JSON request body, add the code which is similar to the following in the call: {"username":"<USER-NAME>;", "password":"<PASSWORD>"}. And for these credentials to be specified in XML, add the code which is similar to the following in the call: <login><username>[email protected]</username><password>customer1pw</password></login>

Examples

The image below display a token request for the admin account which uses a REST client:

!

In the example below, the curl command is used to request a token for a customer account:

curl -X POST "https://magento.host/index.php/rest/V1/integration/customer/token" \
     -H "Content-Type:application/json" \
     -d "{"username":"[email protected]", "password":"customer1pw"}"

And down here is an example which uses XML to makes the same request for a customer account token:

curl -X POST "http://magento.vg/index.php/rest/V1/integration/customer/token" \
     -H "Content-Type:application/xml"  \
     -d "<login><username>[email protected]</username><password>customer1pw</password></login>"

Authentication token response

A response body with the token will be returned if the request is successful. And here is how it looks like:

asdf3hjklp5iuytre

Use token in the Web API request

The authentication token in the header has to be included in all the web APIs which call accesses a resource that requires a permission level higher than anonymous. In order for this to be done, an HTTP is specified in the following format:

Authorization: Bearer <authentication token>

Admin access

Any resources for which they are authorized can be accessed by admins.

For instance, here is how you make a web API call with an admin token:

curl -X GET "http://magento.ll/index.php/rest/V1/customers/2" -H "Authorization: Bearer vbnf3hjklp5iuytre"

Customer access

Only resources with self permissions can be accessed by customers.

For instance, here is how you make a web API call with a customer token:

curl -X GET "http://magento.ll/index.php/rest/V1/customers/me" -H "Authorization: Bearer asdf3hjklp5iuytre"

OAuth authentication

The OAuth authentication in Magento is developed based on OAuth 1.0a, which is an open standard for secure API authentication. OAuth is considered as a token-passing mechanism which allows a system to decide which external applications gain access to internal data without any user IDs or passwords be revealed or stored.

In Magento, integration is a third-party extension which uses OAuth for authentication. The resources which the extension can access are defined by the integration. The extension can access all resources or a customized subset of resources.

As the procedure of registering the integration proceeds, tokens which the extension required for authentication are created by Magento. Firstly, a request token will be created. This is a short-lived token and has to be exchanged for access tokens which are long-lived ones and would not expire if the merchant doesn’t revoke access to the extension.

The below diagram will show the process of OAuth authentication:

!

  • Step 1 - Create an integration: This is the step where an integration will be created from Admin. A consumer key and secret are generated by Mageplaza.

  • Step 2 - Activate the integration: The process starts when the integration is activated. The OAuth consumer key, secret, an OAuth verifier, and the store URL are sent to the external application through HTTPS post to the page defined which is in the Callback Link field in Admin. You can view Activate integration for more details.

  • Step 3 - Process activation information: The activation information which is received in step 2 must be stored in the integrator. These parameters will then be used to ask for tokens.

  • Step 4 - Call the application’s login page: The page defined is called in the Identity Link field in Admin.

  • Step 5 - Merchant logs in to the external application: Once the login is successful, the application will return to the location which is specified in the call. The login page will be dismissed.

  • Step 6 - Ask for a request token: POST /oauth/token/request REST API are used to ask for a request token. The consumer key and other information are included in the Authorization header. View Get an access token for more details about this token request.

  • Step 7 - Send the request token: A request token and request token secret are returned by Magento.

  • Step 8 - Ask for an access token: POST /oauth/token/access REST API are used to asking for an access token. The request token and other information are included in the Authorization header. View Get access token for more details about this token request.

  • Step 9 - Magento sends the access token: An access token and access token secret are returned if this request is successful.

  • Step 10 - The application can access Magento resources: All the request which are sent to Magento have to use the full set of request parameters that are in Authorization header. View Access the web APIs for more information.

Activate integration

The integration has to be configured by selecting System > Extensions > Integrations. A callback URL and identity link URL are included in the configuration. While the callback URL specifies the place where OAuth credentials can be sent using OAuth for token exchange, the identity link identifies the third-party application’s login page which is integrating with Magento.

A merchant can select Save and Activate when the integration is created or he/ she can click on the Activate button against an integration which is previously saved from the Integration grid.

Once the integration is created, a consumer key and a consumer secret will be generated by Magento.

Activating the integration would help submit the credentials to the endpoint specified when the Integration is created.

The following attributes will be included in an HTTP POST from Magento to the Integration endpoint:

  • store_base_url For instance, http://my-magento-store.com/.
  • oauth_verifier
  • oauth_consumer_key
  • oauth_consumer_secret

The oauth_consumer_key key is used to get a request token and the oauth_verifier is used to get an access token.

OAuth handshake details

Completing the OAuth handshake’s process requires you have to

This procedure is also known as a 2-legged OAuth handshake.

Get request token

A request token is a temporary token which is used to exchange for an access token. To get a request token from Magento, you can use the following API: POST /oauth/token/request

These request parameters have to be included in the Authorization header in the call:

Parameter Description
oauth_consumer_key It is generated when the integration is created.
oauth_signature_method It is the signature method’s name which is used to sign the request. It must be the value HMAC-SHA1.
oauth_signature It is a generated value (signature)
oauth_nonce It is a random value which is generated by the application in a unique way.
oauth_timestamp It is a positive integer which is expressed in the number of seconds since January 1, 1970 00:00:00 GMT.
oauth_version It is the version of the OAuth.

The following fields are contained in the response:

  • oauth_token: The token is used when an access token is requested.
  • oauth_token_secret: A secret value which establishes the token’s ownership.

A response which is valid will look smilar to the following one: oauth_token=4cqw0r7vo0s5goyyqnjb72sqj3vxwr0h&oauth_token_secret=rig3x3j5a9z5j6d4ubjwyf9f1l21itrr

Get access token

The request token has to be exchanged for an access token. The following API can be used to get an access token from Magento: POST /oauth/token/access

These request parameters have to be included in the Authorization header in the call:

Parameter Description
oauth_consumer_key It is the consumer key value which is retrieved after the integration is registered.
oauth_nonce It is a random value which is generated by the application in a unique way.
oauth_signature_method It is the signature method’s name which is used to sign the request. It must be the value HMAC-SHA1.
oauth_signature It is a generated value (signature)
oauth_timestamp It is a positive integer which is expressed in the number of seconds since January 1, 1970 00:00:00 GMT.
oauth_version It is the version of the OAuth.
oauth_token It is the request token which is obtained in Get request token.
oauth_verifier It is the verification code which is tied to the consumer as well as request token. When you activate the integration, this code will be sent as a part of the initial POST operation.

Here is how a response which is valid look like:

oauth_token=0lnuajnuzeei2o8xcddii5us77xnb6v0&oauth_token_secret=1c6d2hycnir5ygf39fycs6zhtaagx8pd

These two fields will be included in the response:

  • oauth_token: The access token which gives access to resources that are protected.
  • oauth_token_secret: The secret which is associated with the access token.

Access web APIs

After authorizing the Integration to make API calls, third-party extensions which register as Integrations in Magento can invoke Magento web APIs using the access token.

In order for the access token to be used to make web API calls: GET /rest/V1/products/1234

These request parameters have to be included in the Authorization request header in the call:

  • oauth_consumer_key - The customer key value which is provided after the extension is registered.
  • oauth_nonce - A random value which is uniquely generated by the application.
  • oauth_signature_method - The signature method’s name which is used to sign the request. HMAC-SHA1, RSA-SHA1, and PLAINTEXT are the valid values.
  • oauth_signature - A generated value (signature).
  • oauth_timestamp - A positive integer which is expressed in the number of seconds since January 1, 1970 00:00:00 GMT.
  • oauth_token - The access token, value which is obtained in Get access token.

OAuth signature

The signature is included in all OAuth handshake requests and Web API requests as a part of Authorization header. Following are how it’s generated:

A set of URL-encoded attributes and parameters are concatenated to build the signature base string.

These following attributes and parameters are concatenated by using the ampersand and character.

  • HTTP method
  • URL
  • oauth_nonce
  • oauth_signature_method
  • oauth_timestamp
  • oauth_version
  • oauth_consumer_key
  • oauth_token

The signature can only be generated by using the HMAC-SHA1 signature method. The signing key is the consumer secret and token secret’s concatenated values which are separated by the ampersand and character (ASCII code 38). Parameter encoding has to be used in order to encode each value.

Example of OAuth token exchange

The scripts which are provided in this post simulate the OAuth 1.0a token exchange flow of Magento 2. These scripts can be dropped under the document root directory of your Magento application. This would help these scripts be exposed as endpoints which the Magento application can interact with to imitate the token exchange.

Below is the OAuth 1.0a token exchange flow:

  • Step 1: Login your Magento Admin, then go to System > Extensions > Integrations
  • Step 2: Select Add New Integration
  • Step 3: Fill in all fields which in the Integration Info tab including:
    • Name: Enter the name fo the Integration
    • Callback URL: http://your_app_host/endpoint.php
    • Identity link URL: http://your_app_host/login.php
    • Add permissions as desired on API tab
  • Step 4: From the drop-down menu, choose the Save and Activate option
  • Step 5: In this step, a pop-up window will be displayed which confirms the API permissions. Click on the Allow button. The credentials will be posted to endpoint.php. In this step, you should also see a pop-up for identity linking step which opens the script from login.php.
  • Step 6: Click on Login. The checklogin.php script will be called. The posted credentials are used to complete the token exchange.
  • Step 7: When the token exchange success, the user will be redirected to the Integrations grid. And the integration which is created recently should be in the Active state.
  • Step 8: You can check the Integration Details on the Integration Info tab by clicking the edit icon. All the credentials which can be used to make an authenticated API request using OAuth 1.0 should be shown here.

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>&nbsp;</td>
                        <td>&nbsp;</td>
                        <td><input type="submit" name="Submit" value="Login"></td>
                    </tr>
                </table>
            </td>
        </form>
    </tr>
</table>
HTML;

OauthClient.php

In these example, you can change the instances of http://magento.host to a valid base URL.

<?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://magento.host/oauth/token/request');
    }

    /**
     * Returns the authorization API endpoint.
     *
     * @throws \OAuth\Common\Exception\Exception
     */
    public function getAuthorizationEndpoint()
    {
        throw new \OAuth\Common\Exception\Exception(
            'Magento 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;
    }
}

Session authentication

Similar to customers who login to the Magento storefront with their credentials, admins also need admin credentials to login to their Magento Admin.

With Magento web API framework, your logged-in session information will be used to verify your identity and approve access to the requested resource.

Resources which are configured can be accessed by customers who have anonymous or self permission in the webapi.xml configuration file.

Admin will be able to access resources which are assigned to their Magento Admin profile.

For instance, if a customer login to the Magento storefront and the self API is invoked by the JavaScript widget, the details for the logged-in customer will be fetched: GET /rest/V1/customers/me

Likewise, if an admin login to the Magento storefront and the JavaScript widget Magento_Customer::group API, details for the logged-in admin will be fetched. The identity of the admin user will be established according to logged-in session information and authorizes access to the Magento_Customer::group resource.

Conclusion

Above I have just provided you the information about API Authentication: Token, OAuth, Session Authentication in details. I hope this article is useful. Should you have any questions or new ideas, feel free to leave a comment below.

Enjoyed the tutorial? Spread it to your friends!