i am new to JWT concepts while i am learning in this site
https://code.tutsplus.com/tutorials/jwt-authentication-in-angular--cms-32006
in the above link at this line :
var token = jwt.sign(user, JWT_Secret);
he has written the jwt.sign() with only two parameters but while i saw few other posts where they are sending 3 parameters
my doubt is that jwt.sign() is correct
2) how to create a secret_token
3) and how to send all the required parameters to send in the jwt.sign() method
please help me i hope you understood my problem ,friends please help me
If you read the JWT docs, the function can run in two modes: Synchronously (sync) and asynchronously (async). The function can automatically decide on which method to use depending on the number of parameters and type of parameters you provide the function, and the parameters you can supply are (in order):
The data/payload
Secret key/token
Options/configs (optional, can use callback here if you use default options)
Callback function (optional, will run in async mode if you provide this)
To illustrate this, read the code below:
// Synchronous
const syncToken = jwt.sign({payload: { x: 1, y: '2'}}, 'JWT_SECRET');
console.log(syncToken);
// Asynchronous
jwt.sign({payload: { x: 1, y: '2'}}, 'JWT_SECRET', (err, asyncToken) => {
if (err) throw err;
console.log(asyncToken);
});
As for the secret token, just make a hard coded one with no need to randomize, otherwise you wouldn't be able to consistently verify your tokens if at all possible. Or as an alternative, you can perform signing and verification asymmetrically by using algorithms such as RS256, or ES256 (using public and private key pair).
I hope this answer helps.
Reference:
https://github.com/auth0/node-jsonwebtoken
Related
With the Admin SDK it's possible to further enrich the administration in Shopware 6. As in the installation guide for apps stated, an entry point (base-app-url) needs to be provided in the manifest file of an app.
Since every request needs to be authenticated properly, this GET request also needs authentication. However, I am not able to authenticate this one in the same way as I am successfully doing it with the GET request from modules.
The base-app-url request looks the following (in my case with some [custom] entity privileges):
http://localhost:3000/sdk?location-id=sw-main-hidden&privileges=%7B%22read%22%3A%5B%22language%22%2C%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22create%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22update%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22delete%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%7D&shop-id=sbzqJiPRrbHAlC2K&shop-url=http://localhost:8888×tamp=1674045964&sw-version=6.4.18.0&sw-context-language=2fbb5fe2e29a4d70aa5854ce7ce3e20b&sw-user-language=de-DE&shopware-shop-signature=e7b20a46487046a515638f76c6fadab6b1c749ea4a8ac6e7653527e73ba18380
The shop has the following data
Shop {
_id: 'sbzqJiPRrbHAlC2K',
_url: 'http://localhost:8888',
_secret: '3c5a2f031006791f2aca40ffa22e8febbc8a53d8',
_apiKey: 'SWIAB2PVODCWSLZNDMC5ZM1XWA',
_secretKey: 'VnNwM0ZOMnN1Y05YdUlKazlPdlduWTdzOHhIdFpacjVCYkgzNEg'
}
I am currently authenticating my modules like the following (Node.js):
const SHOPWARE_SHOP_SIGNATURE = 'shopware-shop-signature';
export function authenticateGetRequest(req: Request, shop: Shop): void {
// e7b20a46487046a515638f76c6fadab6b1c749ea4a8ac6e7653527e73ba18380
const signature = getSignatureFromQuery(req);
verifySignature(shop.secret, removeParamsFromQuery(req), signature);
}
function getSignatureFromQuery(req: Request): string {
if (!req.query[SHOPWARE_SHOP_SIGNATURE]) {
throw new Error('Signature is not present in request!');
}
return req.query[SHOPWARE_SHOP_SIGNATURE] as string;
}
function removeParamsFromQuery(req: Request): string {
// Some code
// Returns following string - Does neither work for base-app-url nor for module GET requests:
// 'shop-id=sbzqJiPRrbHAlC2K&shop-url=http://localhost:8888×tamp=1674045964'
// If the string follows this pattern, it works only for modules:
// shop-id={id}&shop-url={url}×tamp={ts}&sw-version={v}&sw-context-language={cl}&sw-user-language={ul}
}
function verifySignature(secret: string, message: string, signature: string): void {
const hmac = crypto.createHmac('sha256', secret).update(message).digest('hex');
if (hmac !== signature) {
throw new Error('Signature could not be verified!');
}
}
However the base-app-url cannot be verified correctly and the "Signature could not be verified!" error is thrown.
What am I doing wrong here?
More info:
Additionally I added a GET request for a module where everything is working:
http://localhost:3000/faq?shop-id=sbzqJiPRrbHAlC2K&shop-url=http://localhost:8888×tamp=1674045963&sw-version=6.4.18.0&sw-context-language=2fbb5fe2e29a4d70aa5854ce7ce3e20b&sw-user-language=de-DE&shopware-shop-signature=0f0889c9e8086c6c3553dc946a01f2ef27b34cd1c55b0c03901b6d8a6a9b6f53
The resulting string can be verified:
shop-id=sbzqJiPRrbHAlC2K&shop-url=http://localhost:8888×tamp=1674045963&sw-version=6.4.18.0&sw-context-language=2fbb5fe2e29a4d70aa5854ce7ce3e20b&sw-user-language=de-DE
Try out following code in some php sandbox environment:
<?php
$message = 'shop-id=sbzqJiPRrbHAlC2K&shop-url=http://localhost:8888×tamp=1674045963&sw-version=6.4.18.0&sw-context-language=2fbb5fe2e29a4d70aa5854ce7ce3e20b&sw-user-language=de-DE';
$secret = '3c5a2f031006791f2aca40ffa22e8febbc8a53d8';
$signature = '0f0889c9e8086c6c3553dc946a01f2ef27b34cd1c55b0c03901b6d8a6a9b6f53';
$hmac = hash_hmac('sha256', $message, $secret);
if (!hash_equals($hmac, $signature)) {
echo 'Signature not valid';
} else {
echo 'Signature valid';
}
SOLUTION:
Express decodes the query strings automatically with req.query depending on your express configuration. Keep in mind to validate the hmac with encoded query params as they are passed from shopware.
In my case the only difference where the decoded privileges and they looked like this:
&privileges={"read":["language","ce_atl_faq_group_faqs","ce_atl_faq_group","ce_atl_faq"],"create":["ce_atl_faq_group_faqs","ce_atl_faq_group","ce_atl_faq"],"update":["ce_atl_faq_group_faqs","ce_atl_faq_group","ce_atl_faq"],"delete":["ce_atl_faq_group_faqs","ce_atl_faq_group","ce_atl_faq"]}
But they need to look like this:
&privileges=%7B%22read%22%3A%5B%22language%22%2C%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22create%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22update%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22delete%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%7D
Looking at the QuerySigner, this is how the signature is generated on the side of Shopware with the actual arguments:
hash_hmac(
'sha256',
'location-id=sw-main-hidden&privileges=%7B%22read%22%3A%5B%22language%22%2C%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22create%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22update%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22delete%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%7D&shop-id=sbzqJiPRrbHAlC2K&shop-url=http://localhost:8888×tamp=1674045964&sw-version=6.4.18.0&sw-context-language=2fbb5fe2e29a4d70aa5854ce7ce3e20b&sw-user-language=de-DE',
'VnNwM0ZOMnN1Y05YdUlKazlPdlduWTdzOHhIdFpacjVCYkgzNEg'
);
// 8034a13561b75623420b06fb7be01f20d97556441268939e9a5222ffec12215a
Given on your side you remove the shopware-shop-signature query param AND that the secrets are equal on both sides, you should be able to regenerate the matching signature.
const crypto = require('crypto');
const message = 'location-id=sw-main-hidden&privileges=%7B%22read%22%3A%5B%22language%22%2C%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22create%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22update%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%2C%22delete%22%3A%5B%22ce_atl_faq_group_faqs%22%2C%22ce_atl_faq_group%22%2C%22ce_atl_faq%22%5D%7D&shop-id=sbzqJiPRrbHAlC2K&shop-url=http://localhost:8888×tamp=1674045964&sw-version=6.4.18.0&sw-context-language=2fbb5fe2e29a4d70aa5854ce7ce3e20b&sw-user-language=de-DE';
const hmac = crypto.createHmac('sha256', 'VnNwM0ZOMnN1Y05YdUlKazlPdlduWTdzOHhIdFpacjVCYkgzNEg').update(message).digest('hex');
// 8034a13561b75623420b06fb7be01f20d97556441268939e9a5222ffec12215a
So in theory your code looks fine. Verify that the query string matches exactly. Things to check:
Maybe your node server decodes the url entities unwantedly?
Does your node serve escape special characters in the query string?
Do the secrets match on both sides?
To consider additionally:
Consider to just point the base-app-url to a static page outside of the scope of your app server instead. As that page will be loaded inside an iframe, you can use client side javascript to read the query parameters and, only if necessary, make requests to your app server using the credentials from inside the iframe. Keep in mind you really only need the authentication if you need to handle personalized data, otherwise you might as well serve static assets without the need for authentication.
I've came across two conflicting pieces of information and was wondering if someone could clarify what is happening. As far as I can tell jwt.sign is using a SHA algorithm to create a unique signature which, I saw on computerphile, is not a reversible process. On their video they explained that cryptographic signatures are not the same thing as encryption, as only encryption is a reversible process.
On that note, once I've created this unique signature and then enter it into jwt.verify as an argument, the code example at the bottom seems to reverse it like an encryption and assign the payload to a variable. So is this Bearer token/signature actually encryption? Also what part of the signature is used for verification, is the header and payload decrypted and ran through the signature process again to check it against the attached signature? Can someone please clarify this process because everything online is very wishy washy and or conflicting about the specifics of what is occurring.
function authenticateToken(req, res, next){
const authHeader = req.headers['authorization']
console.log(req.headers)
const token = authHeader && authHeader.split(' ')[1]
if(token == null) return res.sendStatus(401);
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
if(err) return res.sendStatus(403)
console.log('user ', user)
req.user = user;
next();
})
}
Okay so what i've not understood, is that only the last section of the JsonWebToken represents the hash signature. When the format of the token is as follows xxxx.yyyy.zzzz - where x is the header, y is the payload and z is signature - only z actually represents the SHA key.
When you've authorised the login, the signature is created, with the secret. Which is then checked during authentication, by using the base64 data in x and y. I thought the whole thing was SHA.
I am having an issue with AWS Cognito provided UI.
When I am trying to use the provided UI, I call the endpoint with populated URL:
https://mydomain.auth.ap-northeast-1.amazoncognito.com/login?response_type=token&client_id=123456789&redirect_uri=http://localhost:3000/callback/
Now the problem is that, after authentication, Cognito uses a # to send back the required parameters. The result would look like this:
http://localhost:3000/callback/#id_token=eyJragIsm2PqVpw&access_token=eyJraWQiOiJ&expires_in=3600&token_type=Bearer
I have a hard time reading id_token and access_token in my callback page (which is a vue app).
How can I configure Cognito to use the usual question mark (?) to pass query string, Or, How can I read the passed parameters after hash (#).
I appreciate your advise on this.
If you are using Vue.js router, it is actually pretty easy to process the hash part. Just put this snippet somewhere in your component.
reference: https://router.vuejs.org/api/#the-route-object
let cognitoData = {}
if (this.$route.hash !== "") {
let elementsString = decodeURIComponent(
this.$route.hash.substr(1, this.$route.hash.length)
);
let params = elementsString.split("&");
for (let param of params) {
let values = param.split("=");
cognitoData[values[0]] = values[1];
}
}
// do your business with cognitoData
What is the correct method for setting a client to auto answer with the vLine API for WebRTC calls?
Looking at your comment, it looks like you have figured this out. But for completeness and for future reference I will go ahead and answer.
To auto answer a call, all you have to do is call MediaSession.start() when an incoming call comes in, instead of throwing a prompt to the user.
Here is an example snippet:
client.on('add:mediaSession', onAddMediaSession, self);
// Handle new media sessions
onAddMediaSession(event){
var mediaSession = event.target;
mediaSession.on('enterState:incoming', onIncoming, self);
},
// Handle new incoming calls and autoAccept
onIncoming(event){
var mediaSession = event.target;
// Auto Accept call instead of a prompt
mediaSession.start();
}
Note that you can do this in your code even if you are using the UI Widgets.
When javascript is run in the browser there is no need to try and hide function code because it is downloaded and viewable in source.
When run on the server the situation changes. There are use cases such as api where you want to provide users with functions to call without allowing them to view the code that which is run.
On our specific case we want to execute user submitted javascript inside node. We are able to sandbox node.js api however we would like to add our own api to this sandbox without users being able to toString the function to view the code which is run.
Does anyone have a pattern or know of a way of preventing users from outputting a functions code?
Update:
Here is a full solution (i believe) based on the accepted answer below. Please note that although this is demonstrated using client side code. You would not use this client side as someone can see the contents of your hidden function by simply reading the downloaded code (although it may provide some basic slow down to inspect the code if you have used a minify).
This is meant for server side use where you want to allow users to run api code within a sandbox env but not allow them to view what the api's do. The sandbox in this code is only to demonstrate the point. It is not an actual sandbox implementation.
// function which hides another function by returning an anonymous
// function which calls the hidden function (ie. places the hidden
// function in a closure to enable access when the wraped function is passed to the sandbox)
function wrapFunc(funcToHide) {
var shownFunc = function() {
funcToHide();
};
return shownFunc;
}
// function whose contents you want to hide
function secretFunc() {
alert('hello');
}
// api object (will be passed to the sandbox to enable access to
// the hidden function)
var apiFunc = wrapFunc(secretFunc);
var api = {};
api.apiFunc = apiFunc;
// sandbox (not an actual sandbox implementation - just for demo)
(function(api) {
console.log(api);
alert(api.apiFunc.toString());
api.apiFunc();
})(api);
If you wrap a callback in a function, you can use another function in that scope which is actually hidden from the callback scope, thus:
function hideCall(funcToHide) {
var hiddenFunc = funcToHide;
var shownFunc = function() {
hiddenFunc();
};
return shownFunc;
}
Then run thusly
var shtumCallBack = hideCall(secretSquirrelFunc);
userCode.tryUnwindingThis(shtumCallBack);
The userCode scope will not be able to access secretSquirrelFunc except to call it, because the scope it would need is that of the hideCall function which is not available.