JsonWebTokenError: secretOrPublicKey must be an asymmetric key when using RS256 - node.js

I have the below codes using #types/google-one-tap library in Angular 14 project:
// #ts-ignore
window.onGoogleLibraryLoad = () => {
// #ts-ignore
google.accounts.id.initialize({
client_id: '85464xxxxxx-xxxx.apps.googleusercontent.com',
callback: this.handleCredentialResponse.bind(this),
auto_select: false,
cancel_on_tap_outside: true
});
// #ts-ignore
google.accounts.id.renderButton(
// #ts-ignore
document.getElementById("buttonDiv"),
{ theme: "outline", size: "large", width: "100%" }
);
// #ts-ignore
google.accounts.id.prompt((notification: PromptMomentNotification) => { });
};
}
async handleCredentialResponse(response: CredentialResponse) {
console.warn('this was called')
await this.service.LoginWithGoogle(response.credential).subscribe(
(x: any) => {
console.warn(x, 'this is from the authentication google')
localStorage.setItem("token", x.token);
this._ngZone.run(() => {
this.router.navigate(['/logout']);
})
},
(error: any) => {
console.log(error);
}
);
}
Then this calles the auth service below still in my Angular app:
LoginWithGoogle(credentials: string): Observable<any> {
const header = new HttpHeaders().set('Content-type', 'application/json');
return this.httpClient.post(this.path + "/loginwithgoogle", JSON.stringify({ token: credentials }), { headers: header });
}
}
Then in my server - node.js, I have the below implementation to verify the token:
app.post('/loginwithgoogle', function (req, response) {
console.warn(req.body.token);
const PRIVATE_KEY = 'xxxxx-xxxxxxxxxxx';
console.warn('api called')
const decode = jwt.verify(req.body.token, PRIVATE_KEY.replace(/\\n/g, '\n'), { algorithms: ['RS256'] });
response.json({
login: true,
data: decode
});
});
Upon calling the api, I get the below error:
JsonWebTokenError: secretOrPublicKey must be an asymmetric key when using RS256
Any Idea what I might be missing out?

Related

How to create mock function and have good coverage

I am finding it difficult to have code coverage and mocking request and few functions
cf.service.ts
import { omit } from "lodash";
var request = require('request');
const callForwardConfig = require('../../config/callForwardConfig').callForwardConfig;
import logger from "../../utils/logger";
import { SetCallforwardAs } from '../../interfaces/callforward.interface';
export async function appSerGetCallForwardingState(sid: string, token: string) {
try {
return await callForwardApiCall(sid, token).then((res) => {
return res;
})
} catch (e: any) {
throw new Error(e);
}
}
function callForwardApiCall(sid: string, token: string) {
let callforwardUrl = callForwardConfig.url.as;
return new Promise((resolve, reject) => {
request(`${callforwardUrl}?userId=${sid}`, {
method: 'get',
strictSSL: false,
mode: 'no-cors',
json: true,
headers: { 'Content-Type': 'application/json', Authorization: token},
}, (err: any, response: any, body: any) => {
if (err) {
reject(JSON.stringify(err))
} else {
resolve(body);
}
})
});
}
export async function putAppserCallForward(token: string, callForwardObj: SetCallforwardAs) {
return await updateCallForwardAs(token, callForwardObj).then((res) => {
return res;
})
}
async function updateCallForwardAs(token: string, callForwardObj: SetCallforwardAs) {
let callforwardUrl = callForwardConfig.url.as;
return await new Promise((resolve, reject) => {
let body = {
clusters: callForwardObj.clusters,
name: callForwardObj.name,
destination: callForwardObj.destination,
user: callForwardObj.user
}
logger.info(`App server update cfwrd Request object - ${JSON.stringify(body)}`)
request(`${callforwardUrl}`, {
method: 'put',
strictSSL: false,
mode: 'no-cors',
json: true,
body: body,
headers: { 'Content-Type': 'application/json', Authorization: token},
}, (err: any, response: any, body: any) => {
if (err) {
logger.error(`App server call forward update failure USER - ${callForwardObj.sid}`, JSON.stringify(err));
reject(JSON.stringify(err));
} else {
if (!body['success'])
logger.error(`App server call forward update failure USER - ${callForwardObj.sid} - Error - ${JSON.stringify(body)}`);
else
logger.info(`App server call forward update success USER - ${callForwardObj.sid}`);
resolve(body);
}
})
});
}
I have written test as below:
import createServer from "../../utils/server";
const appserService = require('../../service/provider/appser.service');
const request = require('request');
const app = createServer();
jest.mock('request');
const sid = 'A121';
describe("appserver service", () => {
it("appSerGetCallForwardingState", async () => {
const callForwardApiCallMock = jest.spyOn(appserService, 'callForwardApiCall');
callForwardApiCallMock.mockImplementation(() => {
return Promise.resolve('success');
});
appserService.appSerGetCallForwardingState(sid, 'token').then((res: any) => {
expect(res).toBe('success');
});
});
it("callForwardApiCall", async () => {
request.get.mockResolvedValue({ "success": "true" });
appserService.callForwardApiCall(sid, 'token').then((res: any) => {
expect(res).toBe({ "success": "true" });
});
});
it("callForwardApiCall error", async () => {
request.get.mockRejectedValue(new Error('error'));
appserService.callForwardApiCall(sid, 'token').then((res: any) => {
expect(res).toBe({ "success": "true" });
});
});
});
I am struggling to have good code coverage at - least 90%.
request object also needs to be mocked, and functions are not being exported like callForwardApiCall also not able to access from test file
Here is the report:

Error: Error occurred while verifying paramssubVerifierParams need to equal threshold 1 while using the web3auth/node-sdk

i am recieving Error: Error occurred while verifying paramssubVerifierParams need to equal threshold 1
web3auth.ts
import { Web3Auth } from '#web3auth/node-sdk';
import { CHAIN_NAMESPACES, SafeEventEmitterProvider } from '#web3auth/base';
import { WEB3AUTH } from '../config/globals';
import logger from '../config/logger';
export const web3auth = new Web3Auth({
clientId: WEB3AUTH.clientId,
chainConfig: {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: WEB3AUTH.chainId,
rpcTarget: WEB3AUTH.rpcTarget,
displayName: 'Polygon Mainnet',
blockExplorer: 'https://polygonscan.com',
ticker: 'MATIC',
tickerName: 'Matic',
},
web3AuthNetwork: process.env.NODE_ENV === 'production' ? 'mainnet' : 'testnet',
});
export const connect = async (token: string): Promise<void> => {
try {
const provider = (await web3auth.connect({
verifier: WEB3AUTH.verifier, // replace with your verifier name
verifierId: WEB3AUTH.verifierId, // replace with your verifier id, setup while creating the verifier on Web3Auth's Dashboard
idToken: token, // replace with your newly created unused JWT Token.
subVerifierInfoArray: [
{
verifier: 'ga-google',
idToken: token,
},
{
verifier: 'zt-email',
idToken: token,
},
],
})) as SafeEventEmitterProvider;
if (!provider) logger.error('error');
const ethPrivKey = await provider.request({ method: 'eth_private_key' });
logger.info('ETH Private Key', ethPrivKey);
} catch (error) {
throw error;
}
};
controller.ts
web3authHandler = asyncHandler(async (req: Request, res: Response, next: NextFunction) => {
try {
web3auth.init();
const accessToken: string = res.locals.accessToken;
const data = await connect(accessToken);
console.log('data: ', data);
return new SuccessResponse('Successful web3auth', { data }).send(res);
} catch (error) {
throw error;
}
});
What should i do now? I am completely stuck here. Also provide me with more insights of web3auth. What should I use as the verifier and verifierId?

Testing Cognito JWKS using mock-jwk?

Auth AWS lambda
export const authorizeFinance = async (event) => {
if (event.headers.authorization) {
const token = event.headers.authorization.substring(7);
try {
const verifier = CognitoJwtVerifier.create({
userPoolId: "xyz",
tokenUse: "access",
clientId: "123",
});
const payload = await verifier.verify(token);
if (authLogic(payload)) {
return {isAuthorized: true, context: {AuthInfo: 'Finance'}}
}
return {isAuthorized: false, context: {}}
} catch (e) {
return {isAuthorized: false, context: {}}
}
}
}
Test case in jest using mock-jwks
import createJWKSMock from "mock-jwks";
import {authorizeFinance} from "#functions/auth-finance/handler";
describe('Authenticate finance', () => {
const jwks = createJWKSMock('https://cognito-idp.ap-southeast-2.amazonaws.com/ap-southeast-xyz.', 'well-known/jwks.json');
beforeEach(() => {
jwks.start();
});
afterEach(() => {
jwks.stop();
});
test('should verify the token', async () => {
const token = jwks.token({
aud: 'https://test.auth-domain.com/',
iss: 'https://cognito-idp.ap-southeast-2.amazonaws.com/ap-southeast-xyz',
});
console.log(token);
const event = {
headers: {
authorization: `Bearer ${token}`,
}
};
jest.unmock('axios');
const basicResponse = await authorizeFinance(event);
console.log('jatin', basicResponse);
expect(basicResponse).toEqual({ isAuthorized: false, context: {} });
});
})
Fails
Authentication failed JWK for kid "BlYCji0Uj6V3LAxmK1JHqYgnPJIUUqeiS8YzUf0vfh0=" not found in the JWKS
Authentication failed Missing Token use. Expected one of: id, access

Context is empty in GraphQL middleware

I'm sending from frontend authorization token in headers and then I want to check validity of this token in some endpoints using middleware and context, but context is always empty.
I'm using type-graphql.
Frontend code (I check request in 'Network' tab and I can see my additional header):
private async mutate<T>(
mutation: DocumentNode,
data: unknown,
token?: string
) {
const response = await apolloClient.mutate<T>({
mutation: mutation,
context: {
headers: {
'auth-token': token || '',
},
},
variables: {
data: data,
},
});
return response.data;
}
Resolver code:
#Mutation(() => Token)
#UseMiddleware(authMiddleware)
async login(#Ctx() ctx: unknown, #Arg('data') data: LoginInput) {
console.log(ctx);
...
}
Middleware code:
export const authMiddleware: MiddlewareFn = ({ context }, next) => {
console.log(context);
try {
return next();
} catch (error) {
return next();
}
};
console.log is always equal to {}
I found the cause.
In declaration of ApollorServer the context was missing.
const server = new ApolloServer({
schema,
context: ({ req }) => {
const context = {
req,
};
return context;
},
cors: {
origin: '*',
credentials: true,
},
});

Set Mock Response for JWT Module NodeJS

I am writing Test case using JEST in NodeJs inside AzureFunction.
Im trying to mock JWT module outcome inside my index.test.js , however its not working and getting timedout. I wonder is it the return datatype mismatch? How to set response similar to cb of jwt verify method?
Here is my sample code. Please suggest!
Index.js
const JWT = require('./jwtDecoder')
module.exports = function(context, req) {
try {
JWT(req.body, process.env.jwtsecret, function(err, decoded) {
if (err) {
context.log("Invalid JWT::" + req.body);
context.res = {
headers: {
'Content-Type': 'application/json'
},
status: 400,
body: {
"error": err
}
};
context.done();
} else {
context.log("JWT Authentication Successful:");
context.res = {
headers: {
'Content-Type': 'application/json'
},
status: 200,
body: {
"message": "success"
}
};
context.done();
}
});
} catch (err) {
context.log("Exception in main function, PushHttpFunction:" + err);
context.res = {
headers: {
'Content-Type': 'application/json'
},
status: 500,
body: {
"error": err
}
};
context.done();
}
}
jwtDecoder.js
'use strict';
module.exports = (body, secret, cb) => {
console.log('inside jwtDecoder');
if (!body) {
return cb(new Error('invalid jwt data'));
}
require('jsonwebtoken').verify(body.toString('utf8'), secret, { algorithm: 'HS256' }, cb);
};
index.test.js
let indexTest = require('../index')
const { runStubFunctionFromBindings } = require('stub-azure-function-context')
let JWT = require('../jwtDecoder')
jest.mock("../jwtDecoder.js")
/* verify.mockImplementation(() => () => ({
err: new Error('invalid jwt data'),
decoded: 'ok'
})); */
JWT.mockImplementation(() => new Promise(function(resolve, reject) {
resolve('ok');
}));
beforeAll(() => {
process.env = Object.assign(process.env, {
NODE_ENV: "test",
});
});
describe('Simple Testing', () => {
test('return 200 by mocking simpleFunc response" ', async() => {
let request = {
body: "dummy.jwt.zT5p"
};
const context = await runStubFunctionFromBindings(indexTest, [
{ type: 'httpTrigger', name: 'req', direction: 'in', data: request },
{ type: 'http', name: 'res', direction: 'out' },
], new Date());
console.log('mockedResp::', context);
expect(context.res.status).toEqual(200);
}, 30000);
});
Basically you are mocking wrong, you can keep only this line:
jest.mock('./jwtDecoder.js', () => (res, req, cb) => cb(null, 'ok'))
as you need to mock callback
and remove all this part:
jest.mock("../jwtDecoder.js")
JWT.mockImplementation(() => new Promise(function(resolve, reject) {
resolve('ok');
}));

Resources