Unknown authentication strategy: hapi-auth-bearer-simple - javascript

I am trying to use hapi-auth-bearer-simple module to enable bearer token on my app. However, I am getting the error shown in the title.
I am trying to implement this module to enable token authorisation in my app But I am getting error mentioned below
e:\python_training\Training\Node\Test\Project\Backend\node_modules\hapi\node_modules\hoek\lib\index.js:723
I have a route file
module.exports = [
{
method: 'GET',
path: '/api/{_id?}',
handler: function (request, reply) {
Controller.control.get(request.params, function (err, success) {
console.log(request.params);
if (err) {
reply(unifunc.sendError(err));
} else {
reply(unifunc.sendSuccess(SuccessMsg,success)).code(200);
}
});
},
config: {
description: 'desc',
tags: ['api', 'oV'],
validate: {
headers: unifunc.authorizationHeaderObj,
params: {
o_id: Joi.string().required().trim(),
_id: Joi.string().optional().trim()
},
failAction: unifunc.failActionFunction
},
auth: {
strategy: 'bearer',
scope: ['admin', 'user-{params.id}']
},
plugins: {
'hapi-swagger': {
responseMessages: msgs
}](url)
and a controller file in which I mentioned strategy
var bearerSimple= require('hapi-auth-bearer-simple')
authorization = Authorization.auth; // This plugin has the logic to validate the token and return the error in case it fails and I am passing accesstoken as parameter in a function in that file
var getV = function(server, params, callbackRoute){
server.register(
[{
register: bearerSimple
}], function(err){
if(err){
console.log("Failed to log the plugin",err);
throw err;
}
server.auth.strategy('bearer', 'bearerAuth', {
authorization : authorization
});
});
console.log(params);
async.series([
function(cb){}
]}
complete error message is:
Error: Unknown authentication strategy: bearer in path: /api/orders/{order_id}/vehicles/{_id?}
at Object.exports.assert (e:\python_training\Training\Node\Test\Project\Backend\node_modules\hapi\node_modules\hoek\lib\index.js:723:11)
at e:\python_training\Training\Node\Test\Project\Backend\node_modules\hapi\lib\auth.js:152:14
at Array.forEach (native)
at internals.Auth._setupRoute (e:\python_training\Training\Node\Test\Project\Backend\node_modules\hapi\lib\auth.js:149:24)
at new module.exports.internals.Route (e:\python_training\Training\Node\Test\Project\Backend\node_modules\hapi\lib\route.js:142:47)
at internals.Connection._addRoute (e:\python_training\Training\Node\Test\Project\Backend\node_modules\hapi\lib\connection.js:375:17)
at internals.Connection._route (e:\python_training\Training\Node\Test\Project\Backend\node_modules\hapi\lib\connection.js:367:18)
at wrappedRoute [as _route] (e:\python_training\Training\Node\Test\Project\Backend\node_modules\newrelic\lib\instrumentation\hapi.js:222:29)
at internals.Plugin._apply (e:\python_training\Training\Node\Test\Project\Backend\node_modules\hapi\lib\plugin.js:460:14)
at internals.Plugin.route
Is there any way I can resolve this issue?
Edit:
I modified server.js file and removed the strategy from controller file
I placed strategy in server.js
var validationFunction = Authorization.auth;
console.log(validationFunction);
server.register(
[{
register: bearerSimple
}], function(err){
if(err){
console.log("Failed to log the plugin",err);
throw err;
}
server.auth.strategy('bearer', 'bearerAuth', {
validationFunction : validationFunction
});
});
and in Authorization file looks like this
function rauth(accessToken, cb) {
var criteria = {accessToken: accessToken};
var projection = {};
var options = {limit: 1};
Service.AdminService.getadmin(criteria, projection, options, function (err, data) {
if (err) {
cb(err);
} else if (data && data.length > 0 && data[0]._id) {
console.log(data);
console.log(data.length);
adminId = data[0]._id;
cb()
} else {
cb(UniversalFunctions.CONFIG.APP_CONSTANTS.STATUS_MSG.ERROR.INVALID_ACCESS_TOKEN);
}
});
Now I am getting this error:
Error: options.validateFunc must be a valid function in bearerAuthentication scheme
I have been breaking my head over this problem from days. Could anyone suggest what could be the problem here?
The only problem I found was with the parameters of callback function passed in validateFunction but I can't remove the parameters as those parameters are being defined in another function called getadmin. Could anyone suggest a workaround for this?

Solved in this issue https://github.com/Salesflare/hapi-auth-bearer-simple/issues/69.
The problems were a typo and needed to pass more info back on a successful authorization.

Related

TypeError: AWS.rekognition is not a constructor

const AWS = require('aws-sdk')
AWS.config.loadFromPath('./credentials.json');
AWS.config.update({region:'us-east-1'});
var rekognition = new AWS.rekognition();
var params = {
CollectionId: "sammple",
DetectionAttributes: [
],
ExternalImageId: "facialrekogntition", //TODo
Image: {
S3Object: {
Bucket: "facerekognition12",
Name: "download.jpg"
}
}
};
rekognition.indexFaces(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
Whenever I use node index.js, I am getting the error mentioned in the title.
Note - I have my credentials stored in the JSON file and also installed AWS-SDK for node.
It's new AWS.Rekognition(); basically capital R

TypeError: res.status is not a function

I'm making a function that permits me to upload a picture to imgur in my express api (nodejs),
i'm encoutering an error when calling a function returning a promise:
TypeError: res.status is not a function
at uploadpicture.then
This is my code:
Where error is raised:
router.post('/upload', (req, res, next)=> {
var busboy = new Busboy({headers: req.headers});
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
if(fieldname == 'image') {
// the buffer
file.fileRead = [];
file.on('data', function(data) {
// add to the buffer as data comes in
this.fileRead.push(data);
});
file.on('end', function() {
// create a new stream with our buffered data
var finalBuffer = Buffer.concat(this.fileRead);
upload = uploadpicture(finalBuffer).then((res)=>{ //success request
console.log(res);
res.status(200).json({success: true, message: "Successfully uploaded !", url: res.data.link});
},(err)=>{ //error
res.status(500).json({success: false, message: "Error happenned while uploading !"});
}).catch((error)=>{
console.log(error);
res.status(500).json({success: false, message: "Error happenned while uploading !"});
});
})
}
});
busboy.on('finish', function() {
//busboy finished
});
req.pipe(busboy);
});
And the function :
function uploadpicture(stream){ //get picture stream
return new Promise((resolve, reject)=>{
var options = {
uri: 'https://api.imgur.com/3/image',
method: 'POST',
headers: {
//'Authorization': 'Client-ID ' + config.client_id_imgur // put client id here
},
formData: {
image: stream,
type: 'file'
},
auth: {
bearer: config.access_token_imgur,
}
};
request(options)
.then((parsedBody)=> {
resolve(parsedBody);
})
.catch((err)=> {
console.log(err);
reject(err.toString())
});
});
}
The code works perfectly, but i don't know why suddendly this error happened,
i tried to :
change arrow functions to function(){}
Add next to the route parameters
Nothing worked, Thanks for your help
The accepted answer directly addresses the OP's problem, but I post another solution since you can also encounter this error in other places.
When you have:
api.use((error: ErrorRequestHandler, request: ExpressRequest, response: ExpressResponse) => {
response.status(500).end() // response.status is not a function
})
Because the error handling route must accept 4 arguments for express to identify it as an error middleware.
api.use((error: ErrorRequestHandler, request: ExpressRequest, response: ExpressResponse, next: NextFunction) => {
response.status(500).end()
})
Just adding the next function (or whatever argument you're missing) will fix it.
https://github.com/visionmedia/supertest/issues/416#issuecomment-514508137
At this point:
upload = uploadpicture(finalBuffer).then((res)=>{ //success request
the resis the result of promise uploadpicture function (that is the parsedBody), not the res from the express route. So indeed, it has no status function. Try change the then callback name like:
upload = uploadpicture(finalBuffer).then((otherName)=>{ //success request
You are getting this error:
TypeError: res.status is not a function
Because the order should be (err, res, req, next) not (req, res, err, next),
example below
const errorHandler = (err, req, res, next) => {
const statusCode = res.statusCode === 200 ? 500 : res.statusCode;
res.status(statusCode)
res.json({
message : err.message,
stack :process.env.NODE_ENV === 'production' ? null : err.stack,
})
}
Order of parameters really matters i had error in below code
const getImagesByBrand = async (res) => {
try {
const images = await Image.find();
res.status(200).json(images);
} catch (error) {
res.status(500).json(error);
}
};
I was not giving req as parameter and that was the reason for error i just add req,res and it worked
If you are using the async/await method:
const notifications = await notifications.aggregate({...})
if(notifications){
return res.status(200).json({ data: notifications })
}else{
return res.status(404).json({ message: 'No notifications found'})
}
Make sure that you are including your return statements. Not including a return statement will cause this. Something else that I was doing is I had JSON instead of json, which will most definitely throw an error.

How to handle error and send response in GraphQL

I was starting with GraphQL and I was unable to comprehend how we can throw errors in GraphQL
I went through a couple of articles on the web but almost all of them use Apollo and the code-structure looks very different than how I work.
Consider this piece of code, here where I am making a mutation, now how can send a response message with error and change headers status message in case of error?
AddNewPersonalInfo: {
type: userDashboardType,
args: {
parameter: {
type: userCreationlInputType
}
},
resolve: async (parent, args, context) => {
args.parameter.userId = context.req.headers.userId
//Check if user info already exsist
const checkIfUserInformationExsist = await getSelectedThingFromTable('CatsWork_personal', 'userId', `${userId}`)
if (checkIfUserInformationExsist[0]) {
const error = {
code: 403,
message: 'User info Already exsist'
}
throw new Error(error)
} else {
try {
const addLinkedinUser = await insertIntheTable('personal', payload)
return true
} catch (err) {
console.error(err)
throw new Error(err)
}
}
}
}
What I have faced in one of my projects, it is hard to set the status code of the response. So, I made some custom error response to identify correct statusCode using express-graphql
Below is the example (What I have used in one of my projects):
--------app.js file--------
const graphqlHTTP = require('express-graphql')
app.use('/graphql', (req, res) => {
graphqlHTTP({
schema: GraphQLSchema, //A GraphQLSchema instance from GraphQL.js. A schema must be provided.
graphiql: true,
context: { req },
formatError: (err) => {
const error = getErrorCode(err.message)
return ({ message: error.message, statusCode: error.statusCode })
}
})(req, res)
})
--------getErrorCode function implementation--------
const { errorType } = require('../constants')
const getErrorCode = errorName => {
return errorType[errorName]
}
module.exports = getErrorCode
--------Constant.js file--------
exports.errorName = {
USER_ALREADY_EXISTS: 'USER_ALREADY_EXISTS',
SERVER_ERROR: 'SERVER_ERROR'
}
exports.errorType = {
USER_ALREADY_EXISTS: {
message: 'User is already exists.',
statusCode: 403
},
SERVER_ERROR: {
message: 'Server error.',
statusCode: 500
}
}
Now, we are ready to use our setup.
From your query or mutation, you need to require constant file and return custom error:
const { errorName } = require('../constant')
AddNewPersonalInfo: {
type: userDashboardType,
args: {
parameter: {
type: userCreationlInputType
}
},
resolve: async (parent, args, context) => {
args.parameter.userId = context.req.headers.userId
//Check if user info already exsist
const checkIfUserInformationExsist = await getSelectedThingFromTable('CatsWork_personal', 'userId', `${userId}`)
if (checkIfUserInformationExsist[0]) {
const error = {
code: 403,
message: 'User info Already exsist'
}
throw new Error(errorName.USER_ALREADY_EXISTS) // Here you can use error from constatnt file
} else {
try {
const addLinkedinUser = await insertIntheTable('personal', payload)
return true
} catch (err) {
console.error(err)
throw new Error(errorName.SERVER_ERROR) // Here you can use error from constatnt file
}
}
}
}
--------Error response--------
{
error: [{
"statusCode": 403,
"message": "User is already exists."
}],
data: null
}
We just need to write custom error handling from FS side too.
Note:- formatError: is deprecated and replaced by customFormatErrorFn. It will be removed in version 1.0.0. You can refer customFormatErrorFn.
graphql should be an application level layer that shouldn't (see last paragraph why shouldn't and not doesn't) require http to work. Although in 99% of cases it runs on top of http, because of how convenient it is to do so, graphql is itself a layer 7 protocol.
What does that mean in your case? Well, it means you should not mix concepts from HTTP/REST with concepts from graphql and focus on the latter. The headers error code is a HTTP/REST concept, graphql sends errors in the errors field of the response and the nodejs implementation already catches all your errors and adds them to the list. The HTTP status will be always 200, and your clients shouldn't care and consume your graphql api and not a mix of REST with graphql.
That being said, there are couple of things that REST over HTTP does better. So people, including the developers of Apollo, kinda mixed concepts too, mainly because the graphql standard is not complete (aka, it doesn't have a standard/rule for solving all the problems you might encounter while building an API), so people improvised. I wouldn't recommend graphql yet for any serious project.
Reference
You can specify an error function inside graphqlHTTP like this:
app.use("/graphql", graphqlHTTP({
schema,
graphiql: true,
customFormatErrorFn: err => {
try {
err.details = JSON.parse(err.message);
err.message = Array.isArray(err.details.error) ? err.details.error.join(",") : err.details.error;
return err;
} catch {
return err;
}
}
}));
where err.message might contain a JSON object or a string.
you can use those function to generate specific client and server error functions:
const clientError = error => new Error(JSON.stringify({
success: false,
code: 400,
error
}));
const serverError = ({ name, message, stack }) => new Error(JSON.stringify({
success: false,
error: "Server Error",
code: 500,
name,
message,
stack
}));
const userValidationError = err => {
if (err.name === "ValidationError") return clientError(Object.values(err.errors).map(({ message }) => message));
return serverError(err);
}
module.exports = {
clientError,
serverError,
userValidationError
};
userValidationError function is useful if you have a mongodb validation error.
so that you would use it inside resolve function like this:
try {
const createdDocument = await MongooseDoc.create(data);
return createdDocument;
} catch (err) {
throw userValidationError(err);
}
the response would be
{
"errors": [
{
"message": "error details 1,error details 2",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"document"
],
"details": {
"success": false,
"code": 400,
"error": [
"error details 1",
"error details 2"
]
}
}
],
"data": {
"document": null
}
}
if you want to throw a clientError you throw it outside try catch.
Hopefully this code helps someone send dynamic error messages in graphql.

Syntax Error: unexpected Token {

Here is my Model:
var mongoose = require('mongoose');
var partySchema = new mongoose.Schema({
partyCode: Number,
partyName: String,
mobileNo: String
});
var Party = module.exports = mongoose.model('Party', partySchema);
module.exports.getAllParties = function(callback){
Party.find().lean().exec(function(err, parties){
if (err) return callback(err, null);
callback(null, parties);
});
};
Here is the Route:
router.get('/', function(req, res, next){
//retrieve all parties from Party model
//mongoose.model('Party').find({}, function (err, parties) {
Party.getAllParties(err, parties){
if (err) {
return console.error(err);
} else {
//respond to both HTML and JSON. JSON responses require 'Accept: application/json;' in the Request Header
res.format({
//response in dust or jade files
html: function(){
res.render('Party', {
title: 'Party',
"parties" : parties
});
},
//JSON response will show all parties in JSON format
json: function(){
res.json(parties);
}
});
}
};
});
At line no 9 in Route.js (Here in above code line no.4) I get an error:
Party.getAllParties(err, parties){
Syntax error: {unexpected token
Why is it unexpected? Can't I use a function's body here???
You need to pass in a function instead. A block statement like that outside unfortunately won't work.
This is most likely what you need:
Party.getAllParties(function (err, parties) {
// rest of your logic here
});
You can't place a block statement these when you're calling a function.
It looks like you want something like
Party.getAllParties(function() {
// ...
})
Where you pass an anonomous callback function

hapijs with jade view engine best way to display errors

I would like to display my error message in my jade view after validation.
Jade
H1 Hello world
#error
p #{JSON.stringify(errorMsg)}
div
form(action="/",method="post")
div Foo
div
input(type="text",name="foo")
div
input(type="submit",name="submit")
This is my server code...
server.register(Vision,(err)=>{
if(err){console.log(err)}
server.views({
engines:{
jade:Jade
},
path: 'views',
relativeTo: __dirname });
server.route([
{
method:'GET',path:'/',
handler:(request,reply)=>{
reply.view('index');
}
},
{
method:'POST',path:'/',
handler: (request,reply) => {
console.log("POST '/' ");
const err = {}; // check error and set it
reply.view('index',{errorMsg:err});
},
config:{
validate:{
payload: {
foo: Joi.string().required(),
submit:Joi.string().required()
}
}
}
}
]); });
server.start((err)=>{
if(err){console.log(err);} console.log("server started:"+server.info.uri);
});
Goal is to validate the presence of foo
When the validation kicks in the server responses with a http 400 error which is totally fine and expected for api's. This happens even before the handler function is called.
What is the best way to handle validation error with using a view engine?
I was expecting something like (which is obviously not working)
if(request.error){
reply.view('index',{errorMsg:err});
}
I saw also some answers who dealed with the onPreResponse event to catch it globally. Isn't their a way to do this in the request handler method?
Or any best practise tips?
The docs cover this situation specifically. See the specifics here.
The short version taken directly from the docs looks like this:
const preResponse = function (request, reply) {
const response = request.response;
if (!response.isBoom) {
return reply.continue();
}
// Replace error with friendly HTML
const error = response;
const ctx = {
message: (error.output.statusCode === 404 ? 'page not found' : 'something went wrong')
};
return reply.view('error', ctx);
};
server.ext('onPreResponse', preResponse);
Basically on the preResponse event, check if the response is a boom object. If not, reply normally. If is is a boom object reply with your error page and pass some data into it.
If you are using a JOI object to validate the payload you cannot handle it in the handler.
If you log out the request lifecycle:
server.route({
method: 'POST',
path: '/',
handler: (req, reply) => {
reply('hello');
console.log('handler');
},
config: {
validate: {
payload: {
date: Joi.date().required(),
},
},
},
});
server.ext('onRequest', (request, reply) => {
console.log('onRequest');
reply.continue();
});
server.ext('onPreAuth', (request, reply) => {
console.log('onPreAuth');
reply.continue();
});
server.ext('onPostAuth', (request, reply) => {
console.log('onPostAuth');
reply.continue();
});
server.ext('onPreHandler', (request, reply) => {
console.log('onPreHandler');
reply.continue();
});
server.ext('onPostHandler', (request, reply) => {
console.log('onPostHandler');
reply.continue();
});
server.ext('onPreResponse', (request, reply) => {
console.log('onPreResponse');
reply.continue();
});
And try a valid "date" parameter you will get:
onRequest
onPreAuth
onPostAuth
onPreHandler
handler
onPostHandler
onPreResponse
When you try an invalid parameter, so the validation fails:
onRequest
onPreAuth
onPostAuth
onPreResponse
As you can see the handler is not called at all so you cannot handle it the way you described.
If you don't want to implement the routes as an API and then consume it by your site, I would recommend removing the validate attribute from your config and use Joi.validate() in you handler like so:
server.route({
method: 'POST',
path: '/',
handler: (req, reply) => {
Joi.validate(req.payload, dateSchema, (err, val) => {
if (err) {
reply.view('index', { error: err });
}
reply('the date is valid');
});
},
});
Remember that Joi is throwing an error object so it's not just text.

Categories