How can I change the JWT expire time in FeathersJS? - jwt

I was looking at this question on how to set the sub claim of a JWT in FeathersJS, but when I print hook.params, there is no jwt in there.
Only authenticated, query, route, provider, headers, user and payload.
So I remain with the question: how can I change the expire time of a JWT token in Feathers?

Found it :)
I took a look at the code linked in the post (link has changed, but found it back easily when browsing the git repo) and saw that in params, you just need to create your own jwt object and these options will be merged when creating the JWT.
So, if anyone else stumbles upon this, here is my code:
app.service('authentication').hooks({
before: {
create: [
authentication.hooks.authenticate(config.strategies),
context => {
context.params.jwt = { expiresIn: 10 }; // 10 seconds
}
],
remove: [
authentication.hooks.authenticate('jwt')
]
}
});

For posterity,
you can easily change that in config/default.json:
{
// ...
"authentication": {
"jwtOptions": {
"expiresIn": "2 days" // Or "10h" or just a number which is interpreted as seconds
}
}
}

Related

WooCommerce REST API PUT on Variations does not work

I have logged this issue on GitHub but I understand it will take time to get attention. Is there another way of updating Product Variations?
https://github.com/woocommerce/woocommerce/issues/35555
When I PUT a stock_quantity or price update for a product variation nothing changes. This however works 100% on a product but not a variation. The below will have no effect even though I receive an OK status 200.
PUT: wp-json/wc/v3/products/6360/variations/6361
{
"stock_quantity": 7
}
I also tried using the batch endpoint but also nothing gets updated.
/wp-json/wc/v3/products/6360/variations/batch
"update": [
{
"id":6361,
"stock_quantity": 4
}
]
This is not a bug, I was using Postman and the 200 OK returned confused the issue.
Once I added the required Content-Type:application/json header, the record successfully updated.
I also made use of a deprecated NodeJS library woocommerce-api and later tried with the replacement woocommerce-rest-api but both does not seem to handle this correctly.
I can suggest to rather just axios directly to the woocommerce rest api:
const baseUrl = `${process.env.WOOCOMMERCE_URI}/wp-json/wc/v3/`;
const instance = {
headers: {'Content-Type': 'application/json'},
auth: {
username: process.env.WOOCOMMERCE_KEY,
password: process.env.WOOCOMMERCE_SECRET
}
};
let putUrl = `products/${woocommerceImport.onlineProductId}/variations/${woocommerceImport.onlineVariantId}`;
await axios.put(`${baseUrl}${putUrl}`, {
stock_quantity: stock
}, instance);

strapi get related objects of User

I'm using strapi community edition v3.6.8. I have two different models ,User and CarModel. The User Model is strapi's integrated user model. The relation User: CarModel is 1:n
So I've got a profile page in which I want to fetch the User and their related CarModels. I can't get my head around how to achieve this.
I've read several answers that include creating a service which then fetches the related CarModelobjects but I can't figure out what to put into the service.
So the conclusion I've reached so far is that it is probably best if I just create a custom endpoint which fetches the current user and related objects.
How do I go on about this? This is the code I currently have:
axios.get(`http://localhost:1337/users/currentUser`, {
headers: {
Authorization: `Bearer ${token}`
}
})
In extensions/users-permissions/config I've created a routes.json with this content:
"method": "GET",
"path": "/users/currentUser",
"handler": "User.currentUser",
"config": {
"policies": ["policies.isAuthenticated"]
}
}
in config/policies I've created a is-authenticated.js - File with the following content:
module.exports = async (ctx, next) => {
if (ctx.state.user) {
return await next();
}
ctx.unauthorized(`You're not logged in!`);
};
And lastly in extensions/users-permissions/controllers I've created a User.js file with the following content:
const { sanitizeEntity } = require('strapi-utils');
const sanitizeUser = user =>
sanitizeEntity(user, {
model: strapi.query('user', 'users-permissions').model,
});
module.exports = {
currentUser: async (ctx, next) => {
strapi.query('user').find({id: ctx.id}, ['car-model']);
await next();
}
};
So now my questions would be:
1st: Something is wrong because when trying to GET /users/currentUser I get a 403. What exactly am I doing wrong?
2nd: Is this approach even valid in the first place?
And 3rd: What would be the correct approach to solving this problem? Because somewhere else I've read another approach which included writing a custom service which handles resolving the relation, but this looked very complicated imho, considering I'm simply trying to resolve a relation that already exists in the database.
I've also tried manipulating the users/me endpoint which didn't yield any results (and is probably also discouraged).
Interestingly: when the user logs in, I get the user object and all foreign key relations returned. Only when I query /users/me I get only the user data without relations. So I've read that this is a security feature, but what endpoint is used then, when posting to /auth/local and why does this endpoint return the user and related objects?
Could I use this endpoint instead of /users/me?
Any help to this problem would be greatly appreciated, best regards,
deM
So for anyone else looking for a solution, I figured it out. I added a custom route to currentUser as described above then I added a controller for this route in which I put the following code:
currentUser: async (ctx, next) => {
let carModelsOfUser = await (strapi.query('user', 'users-permissions').findOne({id: ctx.state.user.id}, ['carModels', 'carModels.images', 'carModels.ratings.rating']));
return carModelsOfUser;
}
CAUTION!
This also returns the user's hashed password and other potentially sensitive information.
Strapi offers the sanitizeEntity function to remove sensitive information, but as of now I haven't figured out how to use this in that context, as I'm not using the "raw" user here but instead joining some fields.

Nuxt.js + nuxt-auth module refresh jwt

I have front-end server on nuxt.js and backend in django with django-rest-framework.
Can anyone give me example of refreshing jwt token with nuxt-auth local strategy?
I was tryed save token in vuex store, but this code return undefined
var dr = await this.$auth
.loginWith('local', {
data: {
username: this.username,
password: this.password
}
})
.then(response => {
console.log(response)
})
.catch(e => {
this.error = e + ''
})
You can use custom strategy for save refreshToken: https://auth.nuxtjs.org/reference/schemes
auth: {
strategies: {
local: { _scheme: '~/app/myCustomLocalStrategy.js', /* ... */ }
}
}
I think the approach will vary depending on what you’re doing on the server. The best advice I can offer is to grab the local strategy that exists in nuxt-auth and create a custom strategy based on it.
Nuxt-auth seems to have some hooks into setting and getting refresh tokens but they aren’t documented or particularly well integrated: there’s no hook to a refresh end point for example.
It’s not ideal, but coming up with something workable is possible. For example, you can hook into the user endpoint in your custom strategy and reauthenticate using the refresh token if the user endpoint throws a 401.
You can the local strategy where you can define your endpoint to refresh the authorization token.
Then you declare it as defined here:
refresh_token: {
prefix: '_refresh_token.'
},

slack doesn't recognize github webhook payload format

I'm trying to create a slack app that uses incoming webhooks. I want my github repository to post to slack whenever the wiki is updated. I believe I've set up the webhook on github just fine, because I can see that it is attempting a delivery whenever I update the wiki. However, there's always the error, "no_text". I think this error means slack is expecting an item named "text," but the payload from github provides none. I verified this by trying two curl commands from the command prompt (I'm on windows):
curl -X POST -H "Content-type: application/json" --data "{\"text\":\"Hello, World!\"}" [MY_WEBHOOK_URL]
curl -X POST -H "Content-type: application/json" --data "{\"foobar\":\"Hello, World!\"}" [MY_WEBHOOK_URL]
This first one works as expected; the message "Hello, World!" gets posted to the slack channel I wanted, and I got back the "ok" message from curl. The second one did not work; the message was not posted, and I got back the message "no_text" from curl.
I can think of two possible solutions to this problem:
Change the format of the payload coming from github to include an item called "text" and other properties slack actually recognizes.
Get slack to recognize the format the payload is already in, perhaps by telling it to post the contents of a property other than "text."
I don't know how to accomplish either of these, or if they're even possible. Or perhaps there's another solution I haven't thought of?
Note: I already tried to use the github slack app, but couldn't figure out how to get it to post updates to the wiki. (See my other question if you'd like: slack github integration doesn't find wiki repository)
I'm actually looking to do the same thing as you right now. Because the github and slack hooks are fundamentally different, you will need to have something in the middle to process the github webhooks into a Slack message to be posted via an incoming webhook.
You're going to need to do a couple different things (in no particular order):
Set up Github to send out hooks for the specific events you wish to be notified of.
Configure a middle man (I am currently using AWS SNS and Lambda)
Set up slack for the webhook.
For the github webhooks, you will need to leverage the more powerful github API to create the hook. You could do this with curl, but that's kind of a pain so I am using a JS script to take care of it. You will need to npm install github bluebird in the same directory before running something like this:
var GitHubApi = require("github");
var github = new GitHubApi({
// optional
debug: true,
protocol: "https",
host: "api.github.com", // should be api.github.com for GitHub
pathPrefix: "", // for some GHEs; none for GitHub
headers: {
"user-agent": "ocelotsloth-conf" // GitHub is happy with a unique user agent
},
Promise: require('bluebird'),
followRedirects: false, // default: true; there's currently an issue with non-get redirects, so allow ability to disable follow-redirects
timeout: 5000
});
// user token
github.authenticate({
type: "token",
token: "GITHUB_TOKEN_HERE",
});
// https://mikedeboer.github.io/node-github/#api-repos-createHook
github.repos.createHook({
owner: "ocelotsloth",
repo: "lib-ical",
name: "amazonsns",
events: [
//"commit_comment",
//"create",
//"delete",
//"gollum",
//"issue_comment",
"issues"
//"label",
//"milestone",
//"pull_request",
//"pull_request_review",
//"pull_request_review_comment",
//"push",
//"release"
],
config: {
aws_key: "AWS_KEY",
aws_secret: "AWS_SECRET",
sns_region: "us-east-1",
sns_topic: "SNS_TOPIC_ARN"
},
}, function(err, res) {
console.log(JSON.stringify(res, null, '\t'));
});
I remember following a blog post a while ago about setting up the SNS topic to work properly, but I don't remember exactly where it is anymore. Some googling should help. Also, you should be able to set up your own server for github to send these to and avoid having to set up AWS at all if you want to avoid the complexity. See https://mikedeboer.github.io/node-github/#api-repos-createHook for specific instructions on that method. You will need to use editHook after you create the hook, so either get it right the first time or use edit it. You just need to change the method call to editHook and add the id to the call as well.
Something important to see, you can define all of the different Events that you want github to send to you. For all of these, along with their formats, look at https://developer.github.com/v3/activity/events/types/.
To actually post these events to slack, I have a lambda script that currently looks like this (I literally just started writing this today, and haven't implemented more than just posting issue events, but it should do well as a starting point). For this script, you will need to npm install identify-github-event slack-webhook and have your incoming webhook set up as well.
var identifyGithubEvent = require('identify-github-event');
var SlackWebhook = require('slack-webhook')
// slack's link syntax
function link(url, txt) {
return "<" + url + "|" + txt + ">";
}
exports.handler = function(event, context) {
// 1. extract GitHub event from SNS message
var ghEvent = JSON.parse(event.Records[0].Sns.Message);
var eventType, eventName, numb;
console.log(ghEvent);
var ghEventType = identifyGithubEvent(ghEvent);
if (!ghEventType) {
return;
}
var text = "Event! " + ghEventType;
if (ghEventType === 'IssueCommentEvent') {
var who = link(ghEvent.comment.user.html_url, ghEvent.comment.user.login);
var what = link(ghEvent.issue.html_url, "Issue " + ghEvent.issue.number + ": \"" + ghEvent.issue.title + "\"");
text = who + " commented on " + what;
}
else if (ghEventType === 'IssuesEvent') {
var who = link(ghEvent.sender.html_url, ghEvent.sender.login);
var action = ghEvent.action;
var issueNumber = ghEvent.issue.number;
var issueName = link(ghEvent.issue.html_url, ghEvent.issue.title + "\"");
if (action === "opened" | action === "closed") {
text = {
attachments: [{
"fallback": who + " opened Issue" + issueNumber + ": " + issueName,
"color": "#36a64f",
"pretext": "New issue " + action + ":",
"author_name": ghEvent.sender.login,
"author_link": ghEvent.sender.html_url,
"thumb_url": ghEvent.sender.avatar_url,
"title": "#" + issueNumber + ": " + ghEvent.issue.title,
"title_link": ghEvent.issue.html_url,
"text": ghEvent.issue.body,
"fields": [
{
"title": "Status",
"value": ghEvent.issue.state,
"short": true
},
{
"title": "Labels",
"value": ghEvent.issue.labels.map(label => label.name).join("\n"),
"short": true
}
],
"footer": "lib-ical",
"footer_icon": "https://platform.slack-edge.com/img/default_application_icon.png",
"mrkdwn_in": ["text"]
}]
};
} else return;
}
// 'commit_comment':
// 'create':
// 'delete':
// 'issues':
// 'label':
// 'member':
// 'milestone':
// 'pull_request':
// 'pull_request_review':
// 'pull_request_review_comment':
// 'push':
// 'release':
var slack = new SlackWebhook('https://hooks.slack.com/services/SLACK-WEBHOOK-URL', {
defaults: {
username: 'GitHub -- user/project',
channel: '#CHANNEL-NAME',
icon_emoji: ':github:'
}
})
slack.send(text);
};
It's far from perfect, but it gives a really nice result:
For that specific example it's an issue close, but currently that script will also work on open. The script also does limited markdown processing, so if the issue contains any source blocks, it will be rendered properly inside of slack.
I hope this helps you with your approach, feel free to ask me to elaborate on anything else.

Prediction request end up with "invalid data" errors

I get errors when posting prediction requests, but when posting the same requests from the online interface (from Google's API reference page) works well.
I have also posted a new issue on the Git repository, but it seems that no-one even looks at these issues. How lame of Google !!
Well I am posting predict request, which look like this:
var parameters = {
auth: jwtClient,
project: googleProjectID,
id: 'interest_classifier',
input: {
csvInstance: ["country united states", "/location/location"]
}
};
return prediction.trainedmodels.predict(parameters, function(err, response) {
if (err) {
logger.info(null, "prediction err ", err);
}
logger.info(null, "response from predict ", response);
return callback(null, response);
});
And I get this:
err { [Error: Input data invalid.]
code: 400,
errors:
[ { domain: 'global',
reason: 'invalidValue',
message: 'Input data invalid.' } ] }
To clarify: my trained model contains a value and two textual features.
Again, when running this from the online tool (client side) it works well, only when I run it from my node.js server, does it fail.
What's up with that? Anyone knows?
Could this be some encoding issue? request headers?
EDIT:
this is how i authenticate :
var jwtClient = new google.auth.JWT('*****#developer.gserviceaccount.com', 'keys/key.pem', null, ['https://www.googleapis.com/auth/prediction']);
jwtClient.authorize(function(err, tokens) {
logger.info(null, "authorizing");
if (err) {
logger.info(null, "error ", err);
} else {
return logger.info(null, "authenticated ", tokens);
}
});
OK,
So I've dug into Google's code and found out an important detail that is not properly documented.
I think this might be relevant to other people using this library, not only the ones who use google predict.
So most requests need to include a project id in the parameters, but in some cases you also need to include post data (like in my case).
I was trying to include this post data directly in the parameters like so :
var parameters = {
auth: jwtClient,
project: googleProjectID,
id: 'interest_classifier',
input: {
csvInstance: ["country united states", "/location/location"]
}
};
Now I found (this is not documented !!) that the whole part which belongs to the post data should be included within a "resource" field, like this:
var parameters = {
auth: jwtClient,
project: googleProjectID,
id: 'interest_classifier',
resource:{
input: {
csvInstance: ["country united states", "/location/location"]
}
}
};
I believe this will be relevant to any request which includes post data.
Cheers,
Ilan