Kroger...

Refresh Token Tutorial

In This Tutorial

This tutorial covers how to obtain a new access token once the original has expired. The refresh token is sent to the /token endpoint, and the client receives a new access token in the response.

Introduction to Refresh Tokens

The refresh token allows for the “refresh” of a user’s session without requiring an additional user authentication. When the access token is found to be invalid or expired, the client can use the refresh token to obtain a new access token. The same /token endpoint called in the Authorization Code Flow is used with different parameters. The refresh token is invalidated once the client has used it to get a new access and refresh token. Any further requests using the refresh token will return a 400 Missing/Invalid Refresh Token response from the server.

There are different strategies that can be used by a client to implement the refresh token. Two common strategies are:

  1. The proactive approach: When storing the access token and refresh token, the expiration time of the access token can also be stored and checked at intervals to determine if it is close to expiring. The application can then proactively make the refresh request to avoid an unauthorized response.
  2. The reactive approach: When an API request is made using the access token, the server returns a 401 Unauthorized as shown below. The application then reacts by using the refresh token to obtain a new access token and make the API request again.

401 Unauthorized Response

{
  "error_description": "The access token is invalid or has expired",
  "error": "invalid_token"
}

Example Request

An example token request using the refresh token is shown below.

Example Refresh Token Request

  https://api.kroger.com/v1/connect/oauth2/token \
  -H 'Cache-Control: no-cache' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=refresh_token&refresh_token={{REFRESH_TOKEN}}'

Construct and Execute a Refresh Token Request

The refreshHandler() obtains the stored refresh token and makes a request to the tokenService.getByRefresh() function.

refreshHandler.js file (server side)

export async function refreshHandler(req, res, next) {
    if (!req.body.refreshToken) {
        res.sendStatus(400);
        return;
    }

    try {
        const token = await tokenService.getByRefresh(req.body.refreshToken);
        const result = {
            refreshToken: token.refresh_token,
            access_token: token.access_token
        };

The getByRefresh() function shown below in the token-service.js file builds and executes the token request. The refresh token is passed as the query parameter. The response returns both a new access and new refresh token.

The query parameters should be URL encoded.

token-service.js (server side)

// Parameters imported from .env environment variables
const clientId = process.env.CLIENT_ID;
const clientSecret = process.env.CLIENT_SECRET;
const redirectUrl = process.env.REDIRECT_URL;
// Get token by authorization code (getByAuth)
async function getByAuth(code) {
  const body = `grant_type=authorization_code&code=${encodeURIComponent(
    code
  )}&redirect_uri=${encodeURIComponent(redirectUrl)}`;
  return await get(body);
}

// Get access token using refresh token
async function getByRefresh(refreshToken) {
  const body =
    `grant_type=refresh_token&` +
    `refresh_token=${encodeURIComponent(refreshToken)}`;
  return await get(body);
}

async function get(body) {
  // ClientId and ClientSecret (stored in .env file)
  const encoded = buffer.Buffer.from(`${clientId}:${clientSecret}`, `ascii`);
  // ClientId and clientSecret must be encoded
  const authorization = "Basic " + encoded.toString("base64");
  // Build token URL
  // Base URL (https://api.kroger.com)
  // Version/Endpoint (/v1/token)
  const tokenUrl = `${process.env.OAUTH2_BASE_URL}/token`;

  // Token request
  let tokenResponse = await fetch(tokenUrl, {
    method: "POST",
    headers: {
      "User-Agent": "",
      Authorization: authorization,
      "Content-Type": "application/x-www-form-urlencoded"
    },
    body: body
  });
  // Handle response
  if (tokenResponse.status >= 400) {
    console.log(`tokenResponse error: ${tokenResponse.status}`);
    throw new Error(`tokenResponse failed with status ${tokenResponse.status}`);
  }
  // Return json object
  return await tokenResponse.json();
}

Example Response

A sample JSON response is shown below.

Example Refresh Token Response

    "refresh_token": "FN20LbaF2EWC6MPMWdemBwwnP4ZmX8",
    "expires_in": 172800,
    "access_token": "B2eiLK3F2EwGH4iMWb7mM5bng0Zm03",
    "token_type": "bearer"

Next steps

Now that you have seen a implementation of the refresh token, we recommend checking out our API tutorials to expand your application. The API tutorials cover how to make API requests to the following supported Kroger APIs: