Login to Strapi's Admin Dashboard using the API Token

Backend Mar 4, 2024
This post was inspired by the discussion in the Strapi Forum.
0:00
/0:12

Part 1: Create the endpoint to get user info and JWT token.

In the original discussion, it was achieved by passing a JWT token and user info as the query param to log in to the admin user. But what if we want to login using a static token generated inside the admin dashboard?

First, we need to create a new API using the following command.

yarn strapi generate

On the generated files, change src/api/teleport/routes/teleport.js

module.exports = {
  routes: [
    {
      method: 'GET',
      path: '/teleport',
      handler: 'teleport.login',
      config: {
        policies: [],
        middlewares: [],
      },
    },
  ],
};

, then add the functionality in src/api/teleport/controllers/teleport.js

'use strict';

/**
 * A set of functions called "actions" for `teleport`
 */

const ADMIN_EMAIL = '[email protected]'

module.exports = {
   login: async (ctx, next) => {
    const hasToken = ctx.request.query && ctx.request.query.token;
    const token = hasToken ? ctx.request.query.token : null;

    if (!hasToken) {
      ctx.status = 404;
      return;
    }

    // check token
    const apiTokenService = strapi.services['admin::api-token'];
    const accessKey = await apiTokenService.hash(token);
    const storedToken = await apiTokenService.getBy({accessKey: accessKey});

    if (!storedToken) {
      ctx.status = 404;
      return;
    }

    // Deny access if expired.
    if (storedToken.expiresAt && storedToken.expiresAt < new Date()) {
      ctx.status = 404;
      return;
    }

    // only full-access token
    if (storedToken.type != 'full-access') {
      ctx.status = 404;
      return;
    }

    // get admin user
    const user = await strapi.db.query('admin::user').findOne({
      where: {
        email: ADMIN_EMAIL
      }
    })

    // hide sensitive data
    delete user.password;
    delete user.resetPasswordToken;
    delete user.registrationToken;

    const jwtToken = strapi.plugins['users-permissions'].services.jwt.issue({
      id: user.id
    });

    const payload = JSON.stringify({
      user: user,
      jwtToken
    });

    ctx.redirect('/admin/auth/login?payload=' + payload);
    return
  }
};

In the admin dashboard, we have to set the API to public. and generate a full-access token for later use. Therefore, when we access $URL/api/teleport?token=${token}, it will redirect us to the admin login page, with the payload containing user data and token as the query param.

Part 2: Login the user with the credential previously obtained

Now we need to customize the login page logic, to check if we have payload as a parameter inside the url. However, unlike v3 version, in Strapi v4, we need to do the following works to customize:

First, we need the patch-package package as a dependency.

yarn install patch-package

Editnode_modules/@strapi/admin/admin/src/pages/AuthPage/index.js after installing the package. Add the following lines below the "Redirect the user to the login page if the endpoint does not exist or there is already an admin user or the user is already logged in" code block.

  // if url param has payload
  if (search) {
    const params = new URLSearchParams(search);
    const payload = params.get('payload');

    if (payload) { 
      const { user, jwtToken } = JSON.parse(payload)

      auth.setToken(jwtToken, false);
      auth.setUserInfo(user, false);

      return <Redirect to="/" />;
    }

    else {
      return <Redirect to="/auth/login" />;
    }
  }

A patch file will be generated inside the patches folder, and run yarn build to rebuild the admin dashboard. Open $url/api/teleport?token=${token} again and you should notice it will redirect to the admin dashboard and log in the admin user.

Part 3: Don't forget to apply the patch!

When you are going to deploy Strapi to the server, remember to run the yarn patch-package command to apply the patch before rebuilding the resources.

Tags

Sophie Cao

(she/they, elle/iel, 她/佢)