Is custom JWT Validation available in V4?

@gfritz Thanks for your reply, it helped me a lot in creating authorization through Firebase Phone Auth. But I’m stuck at the verify stage. The authenticate function works correctly. Could you help with writing the verify function? After the code, I’ll provide the context that goes into it.

"use strict";
const { ForbiddenError } = require('@strapi/utils').errors;
const jwt = require('jsonwebtoken');

module.exports = {
  /**
   * An asynchronous register function that runs before
   * your application is initialized.
   *
   * This gives you an opportunity to extend code.
   */
  register({ strapi }) {
    strapi.container.get('auth').register('content-api', {
      name: 'firebase-jwt-verifier',
      
      async authenticate(ctx) {
        const { authorization } = ctx.request.header;
      
        // Check for the presence of a JWT token in the header
        if (authorization) {
          const parts = authorization.split(/\s+/);
          if (parts[0].toLowerCase() === 'bearer' && parts.length === 2) {
            const token = parts[1];
      
            try {
              // Verify and decode the Firebase JWT token
              const decodedToken = await strapi.firebase.auth().verifyIdToken(token);
      
              // Check if the phone number in the JWT token matches the incoming request
              if (decodedToken.phone_number === ctx.request.body.phoneNumber) {
                // Get the user or create a new user based on the phone number
                let user = await strapi.db.query('plugin::users-permissions.user').findOne({
                  where: { phoneNumber: ctx.request.body.phoneNumber }
                });
      
                if (!user) {
                  // If the user does not exist, create a new user
                  user = await strapi.db.query('plugin::users-permissions.user').create({ phoneNumber: ctx.request.body.phoneNumber });
                }
      
                // Set the user in the context state
                ctx.state.user = user;

                // Generate Strapi JWT token
                const jwtToken = await strapi.service('plugin::users-permissions.jwt').issue({ id: user.id });
                ctx.state.user.jwt = jwtToken
      
                // Return successful authentication and user information
                return { authenticated: true, credentials: user };
              }
            } catch (error) {
              // Handle error when verifying or decoding the JWT token
              console.error('Error while verifying Firebase JWT token:', error);
            }
          }
        }
      
        // If authentication fails, return authentication error
        return { authenticated: false };
      },      

      async verify(ctx) {
        try {
          // Check for jwt token in ctx.state.auth
          if (ctx.credentials && ctx.credentials.jwt) {
            const tokenPayload = await strapi.service('plugin::users-permissions.jwt').verify(ctx.credentials.jwt);
            return tokenPayload;
          }
        } catch (error) {
          console.error('Error while verifying JWT token:', error);
        }
        throw new ForbiddenError('Invalid JWT token');
      }       
      
    });
  },

  /**
   * An asynchronous bootstrap function that runs before
   * your application gets started.
   *
   * This gives you an opportunity to set up your data model,
   * run jobs, or perform some special logic.
   */
  bootstrap({ strapi }) {
    const admin = require("firebase-admin");
    const serviceAccount = require("../private/firebase/serviceAccountKey.json");
    admin.initializeApp({
      credential: admin.credential.cert(serviceAccount),
    });

    strapi.firebase = admin;
  },
};

Ctx in verify:

{
  strategy: {
    name: 'firebase-jwt-verifier',
    authenticate: [AsyncFunction: authenticate],
    verify: [AsyncFunction: verify]
  },
  credentials: {
    id: 1,
    username: 'ivstepin',
    email: '...',
    provider: 'local',
    password: '...',
    resetPasswordToken: null,
    confirmationToken: null,
    confirmed: true,
    blocked: false,
    createdAt: '2023-06-04T03:18:58.578Z',
    updatedAt: '2023-06-06T20:00:36.307Z',
    phoneNumber: '...',
    jwt: 'eyJhbGciO ... ePFc'
  },
  ability: null
}
1 Like