How to get the Authorization code in the node OIDC provider - node.js

I implemented node-OIDC-Provider in Node JS I got Id-token but I need authorize-code. So, when I hit this Api(http://localhost:3000/auth?client_id=oidcCLIENT&response_type=code&scope=openid&redirect_uri=http://localhost:3000) it throwing an error('http://localhost:3000/?error=invalid_request&error_description=Authorization%20Server%20policy%20requires%20PKCE%20to%20be%20used%20for%20this%20request'). How to fix this error and get the authorization code
Sample.js
const { Provider } = require('oidc-provider');
var express = require('express')
var app = express()
const oidc = new Provider('http://localhost:3000', {
clients: [
{
client_id: 'oidcCLIENT',
client_secret: '...',
grant_types: ['refresh_token', 'authorization_code'],
redirect_uris: ['http://localhost:3000'],
}
],
interactions: {
url(ctx, interaction) { // eslint-disable-line no-unused-vars
return `/interaction/${interaction.uid}`;
},
},
cookies: {
keys: ['some secret key', 'and also the old rotated away some time ago', 'and one more'],
},
claims: {
address: ['address'],
email: ['email', 'email_verified'],
phone: ['phone_number', 'phone_number_verified'],
profile: ['birthdate', 'family_name', 'gender', 'given_name', 'locale', 'middle_name', 'name',
'nickname', 'picture', 'preferred_username', 'profile', 'updated_at', 'website', 'zoneinfo'],
},
features: {
devInteractions: { enabled: false }, // defaults to true
deviceFlow: { enabled: true }, // defaults to false
revocation: { enabled: true }, // defaults to false
},
jwks: {
keys: [
{
d: 'VEZOsY07JTFzGTqv6cC2Y32vsfChind2I_TTuvV225_-0zrSej3XLRg8iE_u0-3GSgiGi4WImmTwmEgLo4Qp3uEcxCYbt4NMJC7fwT2i3dfRZjtZ4yJwFl0SIj8TgfQ8ptwZbFZUlcHGXZIr4nL8GXyQT0CK8wy4COfmymHrrUoyfZA154ql_OsoiupSUCRcKVvZj2JHL2KILsq_sh_l7g2dqAN8D7jYfJ58MkqlknBMa2-zi5I0-1JUOwztVNml_zGrp27UbEU60RqV3GHjoqwI6m01U7K0a8Q_SQAKYGqgepbAYOA-P4_TLl5KC4-WWBZu_rVfwgSENwWNEhw8oQ',
dp: 'E1Y-SN4bQqX7kP-bNgZ_gEv-pixJ5F_EGocHKfS56jtzRqQdTurrk4jIVpI-ZITA88lWAHxjD-OaoJUh9Jupd_lwD5Si80PyVxOMI2xaGQiF0lbKJfD38Sh8frRpgelZVaK_gm834B6SLfxKdNsP04DsJqGKktODF_fZeaGFPH0',
dq: 'F90JPxevQYOlAgEH0TUt1-3_hyxY6cfPRU2HQBaahyWrtCWpaOzenKZnvGFZdg-BuLVKjCchq3G_70OLE-XDP_ol0UTJmDTT-WyuJQdEMpt_WFF9yJGoeIu8yohfeLatU-67ukjghJ0s9CBzNE_LrGEV6Cup3FXywpSYZAV3iqc',
e: 'AQAB',
kty: 'RSA',
n: 'xwQ72P9z9OYshiQ-ntDYaPnnfwG6u9JAdLMZ5o0dmjlcyrvwQRdoFIKPnO65Q8mh6F_LDSxjxa2Yzo_wdjhbPZLjfUJXgCzm54cClXzT5twzo7lzoAfaJlkTsoZc2HFWqmcri0BuzmTFLZx2Q7wYBm0pXHmQKF0V-C1O6NWfd4mfBhbM-I1tHYSpAMgarSm22WDMDx-WWI7TEzy2QhaBVaENW9BKaKkJklocAZCxk18WhR0fckIGiWiSM5FcU1PY2jfGsTmX505Ub7P5Dz75Ygqrutd5tFrcqyPAtPTFDk8X1InxkkUwpP3nFU5o50DGhwQolGYKPGtQ-ZtmbOfcWQ',
p: '5wC6nY6Ev5FqcLPCqn9fC6R9KUuBej6NaAVOKW7GXiOJAq2WrileGKfMc9kIny20zW3uWkRLm-O-3Yzze1zFpxmqvsvCxZ5ERVZ6leiNXSu3tez71ZZwp0O9gys4knjrI-9w46l_vFuRtjL6XEeFfHEZFaNJpz-lcnb3w0okrbM',
q: '3I1qeEDslZFB8iNfpKAdWtz_Wzm6-jayT_V6aIvhvMj5mnU-Xpj75zLPQSGa9wunMlOoZW9w1wDO1FVuDhwzeOJaTm-Ds0MezeC4U6nVGyyDHb4CUA3ml2tzt4yLrqGYMT7XbADSvuWYADHw79OFjEi4T3s3tJymhaBvy1ulv8M',
qi: 'wSbXte9PcPtr788e713KHQ4waE26CzoXx-JNOgN0iqJMN6C4_XJEX-cSvCZDf4rh7xpXN6SGLVd5ibIyDJi7bbi5EQ5AXjazPbLBjRthcGXsIuZ3AtQyR0CEWNSdM7EyM5TRdyZQ9kftfz9nI03guW3iKKASETqX2vh0Z8XRjyU',
use: 'sig',
}, {
crv: 'P-256',
d: 'K9xfPv773dZR22TVUB80xouzdF7qCg5cWjPjkHyv7Ws',
kty: 'EC',
use: 'sig',
x: 'FWZ9rSkLt6Dx9E3pxLybhdM6xgR5obGsj5_pqmnz5J4',
y: '_n8G69C-A2Xl4xUW2lF0i8ZGZnk_KPYrhv4GbTGu5G4',
},
],
},
});
// express/nodejs style application callback (req, res, next) for use with express apps, see /examples/express.js
app.get('/sample', function (req, res) {
res.send('hello world')
})
app.use(oidc.callback())
// or just expose a server standalone, see /examples/standalone.js
const server = app.listen(3000, () => {
console.log('oidc-provider listening on port 3000, check http://localhost:3000/.well-known/openid-configuration');
});
How to set authorization server policy in the OIDC using node(Authorization Server policy requires PKCE to be used for this request')

I believe you need to set these options:
pkce: {
required: true
},
token_endpoint_auth_method: "none"
Also, if using PKCE, you should be sending the standard code_challenge and code_verifier methods as in steps 4 and 8 of my blog post.

Related

How to configure extraQueryParameters for redirect request in MSAL.js

My react app uses MSAL (#azure/msal-browser) for user authentication, so I configure MSAL instance in my index.tsx using configuration object:
const config = {
clientId: "myAppId",
msalConfig: {
auth: {
authority: "signUpSignInCustomPolicyURI",
clientId: "myAppId",
knownAuthorities: ["myB2CTenant.b2clogin.com"],
redirectUri: "/"
},
cache: {<cacheconfig>}
},
loginScopes: ['openid', 'offline_access'],
authorities: {
signUpSignIn: "signUpSignInCustomPolicyURI",
forgotPassword: "forgotPasswordCustomPolicyURI",
}
}
msalInstance = new PublicClientApplication(config);
Then I wrap my app component in MsalProvider component:
<MsalProvider instance={msalInstance}>
<App/>
</MsalProvider>
and use <MsalAuthenticationTemplate> in protected components so users are prompted to login automatically.
On the other hand, we have an ability to add extra parameters to RequestRedirect like this:
const { instance } = useMsal();
const loginRedirectRequest = {
scopes: <myLoginScopes>,
extraQueryParameters: {
locale: "localeId",
theme: "themeId"
}
};
instance.loginRedirect(loginRedirectRequest);
My question is how to configure MSAL instance so it would apply extraQueryParameters every time it redirects users automatically?
Add it into the MSAL config object to start with.
const config = {
clientId: "myAppId",
msalConfig: {
auth: {
authority: "signUpSignInCustomPolicyURI",
clientId: "myAppId",
knownAuthorities: ["myB2CTenant.b2clogin.com"],
redirectUri: "/"
},
cache: {<cacheconfig>}
},
loginScopes: ['openid', 'offline_access'],
authorities: {
signUpSignIn: "signUpSignInCustomPolicyURI",
forgotPassword: "forgotPasswordCustomPolicyURI",
},
extraQueryParameters: {
locale: "localeId",
theme: "themeId"
}
}
msalInstance = new PublicClientApplication(config);

prevent ffmpeg from opening console window

I have a node/express server which is used to give streams from IP camera to a website. Everything is working well. I run that webserver with PM2 on a windows server.
The problem : for each stream I have a windows console opening with just nothing logged in. The console reopen when I try to close it.
Is there a way to prevent those console to open ?
Here is the related node.js code :
const { NodeMediaServer } = require('node-media-server');
private _initiate_streams(): void{
DatabaseProvider.instance.camerasDao.getCamerasList().pipe(
take(1)
).subscribe(
(databaseReadOperationResult: DatabaseReadOperationResult<ICamera[]>) => {
if (databaseReadOperationResult.successful === true){
const cameras = databaseReadOperationResult.result;
const tasks = [];
cameras.forEach( camera => {
tasks.push(
{
app : config.get('media_server.app_name'),
mode: 'static',
edge: camera.rtsp_url,
name: camera.stream_name,
rtsp_transport: 'tcp'
}
)
});
const configMediaServer = {
logType: 3, // 3 - Log everything (debug)
rtmp: {
port: 1935,
chunk_size: 60000,
gop_cache: true,
ping: 60,
ping_timeout: 30
},
http: {
port: config.get('media_server.port'),
allow_origin: '*'
},
auth: {
play: true,
api: true,
publish: true,
secret: config.get('salt'),
api_user: 'user',
api_pass: 'password',
},
relay: {
ffmpeg: 'C:\\FFmpeg\\bin\\ffmpeg.exe',
tasks: tasks
}
};
var nms = new NodeMediaServer(configMediaServer)
nms.run();
} else {
// catch exception
}
}
);
}

Structure of object is being modified during POST request

So I send a post request using needle with the following object as body:
{ time: 1533725993910,
rconPort: 52940,
rconPassword: 'muqrxllv',
serverPort: 38950,
unique: 795571399,
publicIP: 'localhost',
mods:
[ { modName: 'clusterio_1.0.0.zip',
hash: '341feb6c60918c83f7f3a6a14a4a308aef18dda6' },
{ modName: 'clusterio_1.13.1.zip',
hash: '6124bb9d3896b030fafbef07c971314f4640759f' },
{ modName: 'clusterio_1.13.0.zip',
hash: '3dde5199f63d87e3e6ea6ef7f522e0df5842dee4' },
{ modName: 'hotpatch-multimod_1.1.4.zip',
hash: '0a780e23c42452bd51ecc5ce808b65842e77dc85' },
{ modName: 'creative-mode_0.0.1.zip',
hash: '9af437c10d3f39f1f3ffb57c942c3a51d3786f0f' },
{ modName: 'clusterio_1.12.0.zip',
hash: '959c82380cad1a6f039de401a98dd70e13ca2224' } ],
instanceName: 'test',
playerCount: '0' }
When I console.log(req.body) in the Express handler I get
{ time: '1533722833600',
rconPort: '52940',
rconPassword: 'muqrxllv',
serverPort: '38950',
unique: '795571399',
publicIP: 'localhost',
mods: [ { modName: [Array], hash: [Array] } ],
instanceName: 'test',
playerCount: '0',
mac: '00-FF-8C-0F-21-F0' }
Upon closer inspection it turns out that the "mods" field now looks like this:
"mods":[{
"modName":[
"clusterio_1.0.0.zip",
"clusterio_1.13.0.zip",
"clusterio_1.13.1.zip",
"hotpatch-multimod_1.1.4.zip",
"creative-mode_0.0.1.zip",
"clusterio_1.12.0.zip"
],"hash":[
"341feb6c60918c83f7f3a6a14a4a308aef18dda6",
"3dde5199f63d87e3e6ea6ef7f522e0df5842dee4",
"6124bb9d3896b030fafbef07c971314f4640759f",
"0a780e23c42452bd51ecc5ce808b65842e77dc85",
"9af437c10d3f39f1f3ffb57c942c3a51d3786f0f",
"959c82380cad1a6f039de401a98dd70e13ca2224"
]}]
For logging the data on the server side I use
var app = express();
app.use(bodyParser.json());
app.use((req,res,next) => {
if(req.originalUrl == "/api/getID"){
console.log(req.body)
}
next()
});
On the client side I do
console.log(payload);
needle.post('localhost:8080/api/getID', payload, needleOptionsWithTokenAuthHeader, function (err, response, body) {
At first I suspected this was an issue with middleware, but as I am logging before all the middleware gets loaded I am not too sure about that anymore.
I have never experienced anything like this, and any help would be appreciated.
Have you tried to use the function JSON.stringify (doc) ?
Formating POST request with tables can be tricky.
To send an object like {a:1, b:{c:2, d:[3, 4]}, e:[5,6]} you have to format your parameters to fit an array associative, so the parameters will be like this:
a=1
b[c]=2
b[d][0]=3
b[d][1]=4
e[0]=5
e[1]=6
To fill a non-associative array you can try the e[]=7 notation.

Webpacking a NodeJS Express API with MySQL throws connection error in mode '-p', not in '-d'

I have a simple Express API where I use MySQL to retrieve my data. I use Webpack 4 to bundle it with a very simple configuration:
'use strict';
const path = require('path');
module.exports = {
entry: './src/main.js',
target: 'node',
output: {
filename: 'gept_api.js',
path: path.resolve(__dirname, 'dist'),
},
node: {
__dirname: true,
},
};
When I use webpack --config webpack.config.js -d for development everything works just fine.
However, when I run webpack --config webpack.config.js -p for production it suddenly doesn't work anymore, and throws an error when it's getting a connection from the pool.
TypeError: Cannot read property 'query' of undefined
at Object.getItem (C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:154359)
at t.db_pool.getConnection (C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:154841)
at c._callback (C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:68269)
at c.end (C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:8397)
at C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:322509
at Array.forEach (<anonymous>)
at C:\Users\freek\Dropbox\Code\Apps\GEPT\GEPTv2_API\dist\gept_api.js:1:322487
at process._tickCallback (internal/process/next_tick.js:112:11)
So somehow this is broken by using the production mode in webpack 4. The connection object undefined somehow, while it isn't in development mode.
I have no idea how to fix this, since I'm a noob in using Webpack. I tried searching on google, but couldn't find anything relevant.
How I create my pool:
'use strict';
var mysql = require('mysql');
var secret = require('./db-secret');
module.exports = {
name: 'gept_api',
hostname: 'https://api.toxsickproductions.com/gept',
version: '1.3.0',
port: process.env.PORT || 1910,
db_pool: mysql.createPool({
host: secret.host,
port: secret.port,
user: secret.user,
password: secret.password,
database: secret.database,
ca: secret.ca,
}),
};
How I consume the connection:
pool.getConnection((err, connection) => {
PlayerRepository.getPlayer(req.params.username, connection, (statusCode, player) => {
connection.release();
res.status(statusCode);
res.send(player);
return next();
});
});
and
/** Get the player, and logs to HiscoreSearch if exists.
*
* Has callback with statusCode and player. Status code can be 200, 404 or 500.
* #param {string} username The player's username.
* #param {connection} connection The mysql connection object.
* #param {(statusCode: number, player: { username: string, playerType: string }) => void} callback Callback with statusCode and the player if found.
*/
function getPlayer(username, connection, callback) {
const query = 'SELECT p.*, pt.type FROM Player p JOIN PlayerType pt ON p.playerType = pt.id WHERE username = ?';
connection.query(query, [username.toLowerCase()], (outerError, results, fields) => {
if (outerError) callback(500);
else if (results && results.length > 0) {
logHiscoreSearch(results[0].id, connection, innerError => {
if (innerError) callback(500);
else callback(200, {
username: results[0].username,
playerType: results[0].type,
deIroned: results[0].deIroned,
dead: results[0].dead,
lastChecked: results[0].lastChecked,
});
});
} else callback(404);
});
}
I found what was causing the issue. Apparantly the mysql package relies on Function.prototype.name because setting keep_fnames: true fixed the production build. (https://github.com/mishoo/UglifyJS2/tree/harmony#mangle-options)
I disabled the Webpack 4 standard minification and used custom UglifyJSPlugin settings:
'use strict';
const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
entry: './src/main.js',
target: 'node',
output: {
filename: 'gept_api.js',
path: path.resolve(__dirname, 'dist'),
},
node: {
__dirname: true,
},
optimization: {
minimize: false,
},
plugins: [
new UglifyJsPlugin({
parallel: true,
uglifyOptions: {
ecma: 6,
mangle: {
keep_fnames: true,
},
},
}),
],
};

jwt config secret file push on git

I work on an node, express mongoose API with JWT (json web token). I don't push my config.js file to keep secret my key (.gitignore -> config.js) but when travis run my test with mocha it return the error : Cannot find module './config'.
I try to mock it but it doesn't work, so :
I can push my config.js file, it's not unsafe ?
How can i mock my require dependency config.js ?
You should push config.js in repo. But you should make it like this:
/*jshint esversion: 6 */
'use strict';
module.exports = function () {
return {
SERVER_HOST: process.env.HOST,
OTP: {
LENGTH: 6,
DURATION: 300000, //ms
},
TWILIO: {
ACCOUNT_SID: process.env.TWILIO_ACCOUNT_SID,
AUTH_TOKEN: process.env.TWILIO_AUTH_TOKEN,
MESSAGE_FROM: process.env.TWILIO_MESSAGE_FROM
},
JWT: {
SECRET: process.env.JWT_SECRET,
ALGORITHM: 'HS512',
ISSUER: 'GOHAN'
},
BCRYPT: {
SALT_ROUNDS: 10
},
EMAIL: {
USER: process.env.EMAIL_USER,
PASSWORD: process.env.EMAIL_PASSWORD
},
REDIS: {
HOST: process.env.REDIS_HOST,
PORT: process.env.REDIS_PORT
},
AWS: {
ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID,
SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY,
S3: {
PROFILE_PIC_BUCKET: process.env.AWS_S3_PROFILE_PIC_BUCKET,
VOICE_MESSAGES_BUCKET: process.env.AWS_S3_VOICE_MESSAGES_BUCKET,
REGION: process.env.AWS_S3_REGION,
SIGNED_URL_EXPIRY: 900
}
},
TCP_SERVER: {
PASSWORD: process.env.TCP_SERVER_PASSWORD
},
GOOGLE_API_KEY: process.env.GOOGLE_API_KEY,
APN: {
CONNECTION: {
production: (process.env.NODE_ENV === 'production'),
cert: process.env.APN_CERT,
passphrase: process.env.APN_PASSPHRASE,
key: process.env.APN_CERT
},
FEEDBACK: {
address: process.env.APN_FEEDBACK_ADDRESS,
cert: process.env.APN_CERT,
key: process.env.APN_CERT,
passphrase: process.env.APN_PASSPHRASE,
interval: process.env.APN_INTERVAL,
batchFeedback: process.env.APN_BATCHFEEDBACK
}
},
FCM: {
API_KEY: process.env.FCM_API_KEY,
RETRY_LIMIT: 3
}
};
};
All the code should be independent of the environment, this is the purpose of environment variables. Not to ensure safety.
You can load up the environment variables before running your app.
You can have different .env files for testing, dev and prod environments also.
EDIT:
The above config.js is from a project of mine.

Resources