'Strapi 4 extend auth.callback login function give 405 routes

I'm trying to add a refresh token to strapi 4 login function when I'm login the user. I've followed this tutorial, which is done on v3. Tutorial link

I'm using Strapi 4 extensions and I modified the strapi-server.js file in ==> src/extensions/users-permissions/strapi-server.js

As explained in the tutorial, I copy/paste all functions of the controller found here (I've only tried callback for the moment)strapi github repo

I've change some path for the require to work, and I the callback is working as before when the user logs in, and I also get my token version 'tkv' and the refresh token id as in the tutorial.

I have 1 question and 1 issue.

  1. Is there a way to avoid duplicating these core functions ? I only want to add a refresh token to the end result.

  2. I've created two new routes to refresh and revoke the token as explained. But, even if I give the authorisations in strapi backend, I still get a "405" Method not allowed when I call the endpoint.

Something I dont understand is that in the default file of strapi-server.js, we have a demo code for the route.

// Original demo code in the existing strapi-server.js 
plugin.policies[newPolicy] = (ctx) => {};
 plugin.routes.push({
 method: 'GET',
 path: '/route-path',
 handler: 'controller.action',
});

If I push the new routes using the example, I get an error, which says that plugin.routes... is not a function

If I change the routes like this, the routes are correctly added :

plugin.routes['content-api'].routes.push({
        method: 'POST',
        path: '/auth/refreshToken',
        handler: 'auth.refreshToken',
      },{
        method: 'POST',
        path: '/auth/revokeToken',
        handler: 'auth.revokeToken',
      })

Here, I get my routes added to the backend, but when I look in strapi backend roles&permissions, the endpoint path of the methods are "/api/users-permissions/auth/refreshToken" or "/api/users-permissions/auth/revokeToken". I don't understand why the controller is added.

If I call these endpoint, I get a 400 error. If I call these endpoint removing the "users-permissions" in the endpoint path, I get a 405.

I don't know where to look at, to correct this to get my tokens. Thank you all for you help.

Regards,

Fabien



Solution 1:[1]

  1. I am not sure, but looks like the core functions have to be replicated

  2. Working code for me as below

plugin.controllers.auth['refreshToken'] = async (ctx) => {
   
    const params = _.assign(ctx.request.body);
  
    // Params should consist of:
    // * token - string - jwt refresh token
    // * renew - boolean - if true, also return an updated refresh token.  // Parse Token
    try {
      // Unpack refresh token
      const {tkv, iat, exp, sub} = await strapi.plugins["users-permissions"].services.jwt.verify(params.token);    // Check if refresh token has expired
      if (Date.now() / 1000 > exp) return ctx.badRequest(null, "Expired refresh token");    // fetch user based on subject
      const user = await strapi.query('plugin::users-permissions.user').findOne({where:{ id: sub }});    // Check here if user token version is the same as in refresh token
      // This will ensure that the refresh token hasn't been made invalid by a password change or similar.
      if (tkv !== user.tokenVersion) return ctx.badRequest(null, "Refresh token is invalid");    // Otherwise we are good to go.
      ctx.send({
        jwt: strapi.plugins["users-permissions"].services.jwt.issue({
          id: user.id,
        }),
        refresh: params.renew ? generateRefreshToken(user) : null
      });
    } catch (e) {
      return ctx.badRequest(null, "Invalid token");
    }
  }

  plugin.controllers.auth['revoke'] = async (ctx) => {
    const params = _.assign(ctx.request.body);
    const userService = getService('user');
  // Params should consist of:
  // * token - string - jwt refresh token  // Parse Token
    try {
      // Unpack refresh token
      const {tkv, iat, exp, sub} = await strapi.plugins["users-permissions"].services.jwt.verify(params.token);    // Check if refresh token has expired
      if (Date.now() / 1000 > exp) return ctx.badRequest(null, "Expired refresh token");    // fetch user based on subject
      const user = await strapi.query('plugin::users-permissions.user').findOne({where:{ id: sub }});    // Check here if user token version is the same as in refresh token
      // This will ensure that the refresh token hasn't been made invalid by a password change or similar.

      if (tkv !== user.tokenVersion) return ctx.badRequest(null, "Refresh token is invalid");    // Update the user.
      const tokenVersion = user.tokenVersion + 1;
       await userService.edit(sub, {
        tokenVersion: tokenVersion
      });


      ctx.send({
        confirmed: true,
      });
    } catch (e) {
      return ctx.badRequest(null, "Invalid token");
    }
  }

  plugin.routes['content-api'].routes.push({
    "method": "POST",
    "path": "/auth/refreshToken",
    "handler": "auth.refreshToken",
    "config": {
      "policies": [],
      "prefix": ""
    }
  });

  plugin.routes['content-api'].routes.push({
    "method": "POST",
    "path": "/auth/revoke",
    "handler": "auth.revoke",
    "config": {
      "policies": [],
      "prefix": ""
    }
  });

Calling /api/auth/refreshToken and /api/auth/revoke works fine afters

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1