Skip to main content

Validate Token

Important

This feature is currently in Early Availability (EA) status. For more information, see our product lifecycle phases.

After fetching the authentication token in your extension app, the token can now be included with the requests to your API.

Before processing the request in your API, it is important to validate the token to ensure that the incoming request is initiated by a marketplace user that is using your extension app. This prevents unauthorized access to your APIs.

Overview

Here is an overview of the steps to validate the token on your API:

  1. Get the JWT authentication token from the request.

    • See JWT reference for more details.
  2. Pull the public key from the marketplace keys endpoint.

    • Every marketplace has a JWKS (JSON Web Key Set) endpoint that provides the public cryptographic keys that was used to sign, and that can be used to validate the token.
  3. Use the public key to validate the authentication token.

  4. If the token is valid, process the request. Otherwise, return an appropriate error response.

Implementation details

The example below demonstrates how to validate the token using a middleware in Node.js with Express. Here are a few notable details:

1. Getting marketplace information

To validate that the request came from your marketplace, the MARKETPLACE_BASE_URL and MARKETPLACE_TENANT should be either defined in an environment variable, or obtained from the request.

2. Enabling CORS (Cross-Origin Resource Sharing)

To allow requests from the marketplace to your API, CORS needs to be enabled on your API server. See CORS reference for details.

3. Getting and securing the auth token

The auth token can be included in your extension app request, then obtained in your API server via the request header, such as the MP-Authorization header shown in this example.

There are also other means to send token, such as via request body, query param, or cookie, but keep in mind the security considerations.

4. Using a JWKS library to connect to public key endpoint

The jwks-rsa library is used to simplify the process of validating an auth token against a set of public keys from a JWKS endpoint.

  • A JWKS client is created to connect to the marketplace public keys endpoint.
  • Inside getKey function, the JWKS client is used to get the specific public key that matches the auth token's key identifier (header.kid), using jwksClient.getSigningKey. The publicKey is returned by the function.

Alternatively, this can also be done without this library with these steps: fetch the keys from the endpoint, find the JWK that matches the token's header.kid, convert the JWK to PEM, then verify the token using that PEM.

5. Using a JWT library to validate the token

The jsonwebtoken library is used to validate the token against the public key returned by the getKey function. jwt.verify returns decoded token and error, if any.

  • If token is invalid or expired, log error in err and return error message.
  • If tenant in decoded token does not match marketplace tenant, log error and return error message.

6. Processing request on successful validation

If token is valid, you can optionally use the user's information in the decoded token. Then you can continue processing the request, by calling next().

Node Validation Middleware Example

const jwt = require('jsonwebtoken');
const jwksRsa = require('jwks-rsa');

// can be obtained from env, or from request
const MARKETPLACE_BASE_URL = 'https://your-marketplace-url'
const MARKETPLACE_TENANT = 'TENANT'

// connect to public keys endpoint of marketplace
const jwksClient = jwksRsa({
jwksUri: `${MARKETPLACE_BASE_URL}/oauth2/certs`
});

const validateToken = async (req, res, next) => {
const token = req.header('MP-Authorization');

if (!token) {
return res.status(401).send('No token provided');
}

// function that gets matching public key from JWKS endpoint
const getKey = (header, callback) => {
jwksClient.getSigningKey(header.kid, (err, key) => {
if (err) {
console.error(`Error fetching public key from: ${MARKETPLACE_BASE_URL}`, err);
return res.status(500).send('Error fetching public key');
}

const publicKey = key.getPublicKey();
callback(null, publicKey);
});
};

// validate token using public key from getKey function
jwt.verify(token, getKey, (err, decoded) => {
if (err) {
console.error('Invalid auth token: ', err);
return res.status(401).send('Invalid auth token');
}

if (decoded?.tenant !== MARKETPLACE_TENANT) {
console.error(`Invalid auth token: tenant in token ${decoded.tenant} does not match marketplace tenant ${MARKETPLACE_TENANT}`);
return res.status(401).send('Invalid auth token');
}

// optional: store user info in request object
req.user = {
name: decoded.name,
tenant: decoded.tenant
};

console.info('Token validated');

next();
});
};

module.exports = validateToken;

Was this page helpful?