Error: secretOrPrivateKey must have a value - mysql

I am using jwt to create token, but when i login via postman I get the error "Error: secretOrPrivateKey must have a value" from my console. I have attached my login code. Please anyone who can help me
exports.login = (req, res, next) => {
User.findOne({
where: {
email: req.body.email
}
})
.then(user => {
if (!user) {
return res.status(401).json({
message:
"Auth failed!! either the account does't exist or you entered a wrong account"
});
}
bcrypt.compare(req.body.password, user.password, (err, result) => {
if (err) {
return res.status(401).json({
message: "Auth failed",
token: token
});
}
if (result) {
const token = jwt.sign(
{
email: user.email,
password: user.id
},
process.env.JWT_KEY,
{
expiresIn: "1h"
}
);
res.status(200).json({
message: "Auth granted, welcome!",
token: token
});
}
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
};
this is my env.json file
{
"env":{
"MYSQL":"jllgshllWEUJHGHYJkjsfjds90",
"JWT_KEY": "secret"
}
}

It looks like your application can't read the environment variable properly.
I don't know which package you are using to load environment variables but the simplest way is using dotenv package.
After installing it with npm i dotenv, import it as early as possible in your application main file like this:
require("dotenv").config();
Create .env file in your application root folder with this content ( as you see the format is key=value)
MYSQL=jllgshllWEUJHGHYJkjsfjds90
JWT_KEY=secret
Then you can access their values like you already did:
process.env.JWT_KEY
.env file:

Remove the process.env.JWT_SECRET_KEY and do it this way: ${process.env.JWT_SECRET_KEY} wrap it with backtick.
It solved the problem for me.

Had this issue with NestJS when trying to rely on process.env.X. Supposedly #nestjs/config uses dotenv in the background but it doesn't work as expected. I either had to use ConfigService or explicitly configure dotenv in the given files:
jwt.strategy.ts
import * as dotenv from 'dotenv';
dotenv.config();
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
secretOrKey: process.env.JWT_SECRET,
});
}
}
or
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(configService: ConfigService) {
super({
secretOrKey: configService.get<string>('JWT_SECRET'),
});
}
}
auth.module.ts
import * as dotenv from 'dotenv';
dotenv.config();
#Module({
imports: [
JwtModule.register({
secret: process.env.JWT_SECRET,
}),
],
})
or
#Module({
imports: [
JwtModule.registerAsync({
imports: [ConfigModule]
useFactory: async (configService: ConfigService) => {
return {
secret: configService.get<string>('JWT_SECRET'),
};
},
inject: [ConfigService],
}),
],
})

It works for me only if I concatenate it with an empty string like this:
"" + process.env.JWT_KEY

simply remove the process.env.JWT_KEY and replace with "secret key using" ES6 String Literals
${process.env.JWT_SECRET_KEY}
it solves this for me

It was accidentally adding the JWTService as a provider in my AuthModule. That, it seems was overriding the defaults I had set up when registering the JWTModule.
What I had before:
#Module({
imports: [
PassportModule,
JwtModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => {
const authConfig = configService.get<AuthenticationConfig>(
PathNames.AUTH,
);
return {
secret: authConfig.accessToken.secret,
signOptions: {
expiresIn: authConfig.accessToken.expiryTime,
},
};
},
}),
],
providers: [
AuthService,
UsersService,
PrismaService,
AuthResolver,
// this was the problem
JwtService,
JWTStrategy,
],
exports: [AuthService],
})
export class AuthModule {}

Are you sure process.env.JWT_KEY has a valid value? I believe it is undefined or null.

Put the require('dotenv').config() at the top of the server.js file
This solved for me

You can try this, it works for me.
"" + process.env.JWT_KEY

I simply removed process.env.JWT_KEY and replace with "secret" and its working fine.

Just add back quotes `` and use the syntax ${process.env.SECRET_KEY} in them.
I also advise you to use the cross-env package, after installing which you can make two files with environment variables .development.env and .production.env
To configure cross-env, just paste this into a package.json "scripts" field:
"start": "cross-env NODE_ENV = production nest start",
"start:dev": "cross-env NODE_ENV = development nest start --watch"
it is for nestjs

To chime in on this, I found this error was being caused by the contents of the key I was trying to use. I regularly use a "password generator" for such strings, and it had given me the following to use:
<B#LCK$^\7(T^fuaQemeR&6s:##AAwe#?T,c'=+kxT?euCP27R/D=uRm893$=^_h^f={c.)MD#[%zg}$K8_D#D-_/tb2?Q>RFr(}H:Fp#{&yNFt#2Y<K\GB28unz
if the above is placed in between back ticks or speech marks it will not be able to be parsed as a string and will therefore cause this error as described above.
As an extra level of de-bugging make sure you first wrap your key in backticks or parenthesis in order to make sure that an un-parsable string isn't the issue.

You can also try and specify an object with a property the path to the configuration file like
require("dotenv").config({path: '/path_to_env_file'});

I also had the same issue I came to realize that the issue was that I didn't include dotenv package
so
import * as dotenv from 'dotenv';
then put dotenv.config() on top before any other implementation

step 1: install dotenv
step 2: import that in app.js:
const dotenv = require("dotenv");
step 3:
dotenv.config(`${process.env.SECRET_KEY}`);
your issue will solve

Check that process.env.JWT_KEY is defined:
console.log(process.env.JWT_KEY)

I have this issue in backend. To solve I create a init.js file, add my config to process.env and require index.js file
const config = require(`<path of config json file>`)
process.env = { ...process.env, ...config }
require('./index')
then get init.js as entry index in webpack

Do not fix this by prepending an emptystring '' + to your JWT or by wrapping it inside of ${process.env.YOUR_JWT}. This resolves the error but doesn't fix the underlying issue.
The problem is actually that dotenv is being invoked after your module code where you try to read from process.env, therefore process.env.ANYTHING_HERE wont have been populated by dotenv yet.
Probably in your entrypoint file (i.e. main.ts you are calling import on app.module before calling into dotenv or nest's wrapper around it.
The comprehensive fix here is to modify main.ts to call require('dotenv').config({ path: './.env' }) or however you bootstrap your env, and to do this before you import any other file. That way, all your imports will have process.env populated with your environment variables before they run.
If you just fix the issue by following the solutions above then you're going to end up setting your secret key to 'undefined' because what you're actually just doing is you're concating empty string with the env variable for your secret before it exists. It solves the error but clearly wont be the secret you wanted from your config file.
It's also not a good idea to fix it this way because you're not solving this issue for your other environment variables either. They still wont be available to your modules where they need them because they're being included after instead of before, and thus you're highly likely to have other issues in your project where your environment variables are undefined elsewhere too.

This message was occured to me only when I was running E2E tests. In my case I had to explicitly set as an secret option to fix it.
this.jwtService.sign(tokenPayload, { secret: `${process.env.JWT_SECRET}` });

In my case using process.env.JWT_SECRET_KEY.replace(/\\n/g, "\n") worked perfectly fine.
I took this reference from how firebase uses keys stored in .env file to parse it. and they use .replace(/\\n/g, "\n") to parse the key.

IN token REPLACE GRAB THE FOLLOWING IN BACKTICKS. THIS SYNTEX WORKED FOR ME TRY THIS.
${process.env.JWT_SECRET_KEY}

Perhaps you use 2 .env files (for development and for production). For example, you use cross-env NODE_ENV=development in package.json file in "start:dev". If it is true, don't forget add
ConfigModule.forRoot({
envFilePath: `.${process.env.NODE_ENV}.env`
}),
to your module file:
#Module({
imports: [
PassportModule,
ConfigModule.forRoot({
envFilePath: `.${process.env.NODE_ENV}.env`
}),
JwtModule.register({
secret: process.env.JWT_KEY,
signOptions: {
expiresIn: '1h'
},
}),
],
providers: [AuthService, LocalStrategy, JwtStrategy],
exports: [AuthService]
})
export class AuthModule {}
Then you haven't to add something to file with class JwtStrategy and another.

${process.env.JWT_SECRET_KEY}
it worked for me by placing it in auth.module.ts

Use the code above(image), to overcome your problem.

This error is coming because .env files is not accessible in auth.js.
so dont write process.env.JWT_KEY
instead of this just write a random string in single quotes.
eg: 'iamtheprogrammer'
ERROR:
const token = jwt.sign({_id:user._id}, process.env.SECRET)
CORRECT CODE:
const token = jwt.sign({_id:user._id},'iamtryingtoaddsome')

Related

Can I use commonjs plugins when running esbuild as a module?

I have an esbuild config taken straight from the docs:
import * as esbuild from 'esbuild'
let ctx = await esbuild.context({
entryPoints: ['./js/app.js'],
outdir: 'static',
bundle: true,
minify: true,
sourcemap: true,
plugins: [
postcss,
],
})
await ctx.watch()
let { host, port } = await ctx.serve({
servedir: 'static',
})
But I need to add some plugins, which are all still in commonjs (the esbuild-postcss plugin is a good example).
When I try to add require('esbuild-postcss') I get the error:
ReferenceError: require is not defined in ES module scope, you can use import instead
Which makes sense - but does this mean I can't use any esbuild plugins until they are converted to es modules?
Note: I know I can go back to a commonjs esbuild config, but as far as I can tell I won't be able to use the serve option if I do that.

"SyntaxError: unexpected token: ':'" when loading JSON file for ngx-translate with Karma runner

I am trying to setup system tests for an Angular app.
It uses the TranslateModule (ngx-translate) like this:
TranslateModule.forRoot({
defaultLanguage: 'de',
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient],
},
missingTranslationHandler: {
provide: MissingTranslationHandler,
useClass: MyMissingTranslationHandler,
},
}),
export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
return new TranslateHttpLoader(http, '/assets/i18n/', '.json');
}
I used a proxy in karma.conf.js to adapt the request and the file is now found by the TranslateLoader.
Still, when I run the tests with Karma I get an error on the Karma server:
An error was thrown in afterAll
SyntaxError: unexpected token: ':'
http://localhost:9876/base/src/assets/i18n/de.json?e0ac90c584fb64b071dedb9301cd9342777ed8a2:2
The JSON file should be working fine, since it can be viewed in the browser (with clicking on that link) and also it works fine under normal development environments.
There needs to be some sort of preprocessor (or similar) since Karma doesn't recognize the JSON file, I suppose.
Anyone got a solution for this?
For me it helped now to set included: false in karma.conf.js under files/pattern where I loaded the JSON file.

How do I limit the scope of `resolveJsonModule`?

I'm working on project that uses Typescript and webpack. I have to import json files, and I have to do it in two ways:
I have to import project's package.json as a module. This has already been implemented previously.
Have to import some json schemas as resources loadable by url. This is what I'm working on right now.
Using package.json (already implemented)
To import package.json, the tsconfig.json contains:
{
"compilerOptions": {
"resolveJsonModule": true,
"paths": {
"package.json": ["./package.json"]
}
},
}
And webpack config has:
/**
* Determine the array of extensions that should be used to resolve modules.
*/
resolve: {
extensions: [".js", ".ts", ".tsx", ".json"],
plugins: [
new TSConfigPathsPlugin({
configFile: path.join(__dirname, "../../tsconfig.json"),
logLevel: "info",
extensions: [".js", ".jsx", ".ts", ".tsx"],
mainFields: ["browser", "main"],
baseUrl: tsConfig.baseUrl,
}),
],
},
And this is how package.json is used:
import packageJson from "package.json";
//...
const release = `${packageJson.version}-${process.platform}`;
This is completely type-safe: ts checks that my package.json has version field. This is working as intended and I don't want to break it.
Using schema json files (what I'm implementing)
To add support for json schemas, I've added them with filenames matching .schema.json$ and have added this to webpack config:
module: {
rules: [
{
test: /\.schema.json$/,
type: "asset/resource",
},
],
},
And this to a global type declaration file:
declare module "*.schema.json" {
declare const uri: string;
export default uri;
}
I thought that by doing that, Typescript would interpret import such a file as a simple string. I've been following this example.
However, when I import the schema file in my project:
import someSchemaUri from "./schemas/some-name.schema.json";
// ...
uri = someSchemaUri;
I still get type error:
Type '{ ... }' is not assignable to type 'string'.
Changing resolveJsonModule
If I set resolveJsonModule option to false, this problem goes away, but importing package.json from the previous section starts giving an error:
Module 'package.json' was resolved to 'secret/path/package.json', but '--resolveJsonModule' is not used.
How do I configure my project so that Typescript would interpret these files as a string, but at the some don't lose type safety when I import package.json from the previous section?
As I know, there's no way to override json types once --resolveJsonModule was set.
May you consider to disable that flag and write types for package.json manually? It's not time-consuming since you use only one package.json field.
declare module '*.schema.json' {
const uri: string;
export default uri;
}
declare module '*package.json' {
const content: {
version: string;
};
export default content;
}

NextJs Webpack asset/source returns JSON as a string

Looking for some help to understand what is going on here.
The Problem
We are using a translation service that requires creating JSON resource files of copy, and within these resource files, we need to add some specific keys that the service understands so it knows what should and should not be translated.
To do this as simple as possible I want to import JSON files into my code without them being tree shaken and minified. I just need the plain JSON file included in my bundle as a JSON object.
The Solution - or so I thought
The developers at the translation service have instructed me to create a webpack rule with a type of assets/source to prevent tree shaking and modification.
This almost works but the strange thing is that the JSON gets added to the bundle as a string like so
module.exports = "{\n \"sl_translate\": \"sl_all\",\n \"title\": \"Page Title\",\n \"subtitle\": \"Page Subtitle\"\n}\n";
This of course means that when I try and reference the JSON values in my JSX it fails.
Test Repo
https://github.com/lukehillonline/nextjs-json-demo
NextJs 12
Webpack 5
SSR
Steps To Reproduce
Download the test repo and install packages
Run yarn build and wait for it to complete
Open /.next/server/pages/index.js to see the SSR page
On line 62 you'll find the JSON object as a string
Open .next/static/chunks/pages/index-{HASH}.js to see the Client Side page
If you format the code you'll find the JSON object as a string on line 39
Help!
If anyone can help me understand what is going wrong or how I can improve the webpack rule to return a JSON object rather than a string that would be a massive help.
Cheers!
The Code
next.config.js
module.exports = {
trailingSlash: true,
productionBrowserSourceMaps: true,
webpack: function (config) {
config.module.rules.push({
test: /\.content.json$/,
type: "asset/source",
});
return config;
},
};
Title.content.json
{
"sl_translate": "sl_all",
"title": "Page Title",
"subtitle": "Page Subtitle"
}
Title.jsx
import content from "./Title.content.json";
export function Title() {
return <h1>{content.title}</h1>;
}
pages/index.js
import { Title } from "../components/Title/Title";
function Home({ dummytext }) {
return (
<div>
<Title />
<p>{dummytext}</p>
</div>
);
}
export const getServerSideProps = async () => {
const dummytext = "So we can activate SSR";
return {
props: {
dummytext,
},
};
};
export default Home;

How do I create a "fat" js file with rollup using esm?

I have the following code..
// ui.js (generated by rollup
import Vue from 'vue';
import VueRouter from 'vue-router';
(()=>{
console.log("Wow it actually works");
Vue.use(VueRouter);
const routes = [
{
path: '/',
component: Viewport
}
];
const router = new VueRouter({
mode: "history",
routes: routes
});
window.app = new Vue({ router });
window.app.$mount('#jg-app');
})();
<script src="ui.js" type="module"> </script>
The problem is when I run this I get...
Uncaught TypeError: Failed to resolve module specifier "vue". Relative references must start with either "/", "./", or "../".
This leads me to believe I need a "fat" js that includes dependencies.
I also want to keep everything in es6 modules and avoid introducing say babel.
Is there a way to do this using rollup?
Update
Tried this...
import Vue from "./vue";
But then I get...
Error: Could not resolve './vue' from src/index.js
As far as I can tell this is not possible. I instead had to move the import from the ui project to the server project and create a static js file that looked like this...
//client
import Vue from "./vue"
let app = new Vue(...);
app.$mount('#jg-app');
and import the esm.browser version
// server
app.use('/vue', express.static(__dirname + '/node_modules/vue/dist/vue.esm.browser.js'));
// template
script(src="/main.js" type="module")
Now Vue is working, however, dependencies like Vue-Router appear to not have this es.browser style file.
This is not a solution, it's a workaround
The below rollup config is not esm, it's just a way to create a bundle with dependencies included.
You get one minified browser-compatible JS file.
Here's my working example rollup.config.js (you should replace input: 'src/index.js' with your web app entry point and output.file with a location for the generated bundle):
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import builtins from 'rollup-plugin-node-builtins';
import babel from 'rollup-plugin-babel';
import visualizer from 'rollup-plugin-visualizer';
import { terser } from "rollup-plugin-terser";
const browserPlugins = [
resolve({browser: true}), // so Rollup can properly resolve cuid
babel({
exclude: 'node_modules/**',
babelrc: false,
presets: ['es2015-rollup'],
}),
// builtins(),
commonjs(),
visualizer(),
terser(),
]
export default [
// browser-friendly UMD build
{
// external: Object.keys(globals),
input: 'src/index.js',
output: {
name: 'thinflux',
file: './dist/browser/thinflux.min.js',
format: 'umd'
},
plugins: browserPlugins,
}
];
One more thing: express should statically serve the output.file path, not your source files