loopback authenticating rest api url - node.js

i have created an endpoint to download csv file but i want to authenticate the endpoint before download, i.e. it should ask for username and password and if verified then only download of csv should happen. i want to do it with loopback only. Any help appreciated. Thanku.
my code for csv download-
Transaction.csvexport = function(type, res, callback) {
res.set('Content-Type','application/download');
res.set('Content-Disposition','attachment;filename=Data.csv');
res.set('Content-Transfer-Encoding','binary');
res.send('ok;'); //#todo: insert CSV data here.
};
Transaction.remoteMethod('csvexport',
{
accepts: [
{arg: 'type', type: 'string', required: true },
{arg: 'res', type: 'object', 'http': {source: 'res'}}
],
returns: {},
http: {path: '/csvexport/:type', verb: 'get'}
});

Authentication is not enabled by default on Loopback. You can create users and set ACLs with the framework. Check out the documentation for more info.

Related

Implement OAuth Implicit Flow in NestJS Swagger

Using the Swagger module provided from NestJS there is no functionality to implement an OAuth connection that automatically get the user token through implicit flows.
From the website there is a lack of documentation about oauth.
https://docs.nestjs.com/openapi/security.
The solution that I've found is using this piece of code
const config = new DocumentBuilder()
.setTitle('Swagger API')
.setVersion('1.0')
.addSecurity('ApiKeyAuth', {
type: 'apiKey',
in: 'header',
name: 'token',
})
.addBearerAuth()
.addOAuth2(
{
type: 'oauth2',
flows: {
implicit: {
tokenUrl: `${configSv.get("OAUTH_DOMAIN")}/oauth/token`,
authorizationUrl: `${configSv.get("OAUTH_DOMAIN")}/authorize`,
scopes: {"read:products": null, "read:properties": null, "read:categories": null, openid: null, profile: null, email: null},
},
},
},
)
.build();
But doesn't retrieve correctly the token and scopes aren't working, facing a 403 error calling the endpoints

How to get user information using node oidc provider

I got access token and I will pass access_token to userinfo endpoint it throwing an invalid token provided error How to fix this Issue. I tried to debug why this error is throwing we have validateAccessToken method(userinfo.js) in this method check the access_token is exist or not exist using this code await ctx.oidc.provider.AccessToken.find(accessTokenValue); when i print this result it's showing undefined
oidc_configuration.js
const oidc = new Provider('http://localhost:3000', {
clients: [
{
client_id: 'oidcCLIENT',
client_secret: '...',
grant_types: ['refresh_token', 'authorization_code'],
redirect_uris: ['http://sso-client.dev/providers/7/open_id', 'http://sso-client.dev/providers/8/open_id'],
}
],
interactions: {
url(ctx, interaction) { // eslint-disable-line no-unused-vars
return `/api/v1/open_id/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',
},
],
},
});
// Heroku has a proxy in front that terminates ssl, you should trust the proxy.
oidc.proxy = true;
const callback = oidc.callback();
How to fix this issue
You're running without a persistent adapter, meaning an in-memory one is used, are you possibly restarting your server after receiving the access token before calling the userinfo endpoint?
After completing the authentication, you will get access_token as well as id_token. I think you were using id_token in place of access_token which is why you are seeing that error
Instead use access_token then you can see the details

Creating forms in Aposstrophe CMS

I am following this tutorial to create a form in my project, which is leveraging the Apostrophe CMS. When i follow the tutorial, I am able to create the form and submit, and understand how to view the form submission in the Admin Console.
However, when I begin to customize the form to fit my project-specific needs, I break the form, causing the form validation to fail. The error i get upon submitting the form is:
TypeError: Cannot read property 'length' of undefined
at Object.convertString [as convert] (user.js:727)
at user.js:145
at async.js:181
at iterate (async.js:262)
at Object.async.forEachOfSeries.async.eachOfSeries (async.js:281)
at Object.async.forEachSeries.async.eachSeries (async.js:214)
at Object.self.convert (user.js:127)
at convert (always.js:57)
at async.js:718
at iterate (async.js:262)
My changes, other then adjusting the field definition object of my contact-form:index.js file, are mostly in the contact-form-widgets:widget.html file.
In the tutorial, the contact-form-widgets:widget.html view imports apostrophe-schemas:macros.html, and uses html files from the apostrophe-schemas and apostrophe-ui modules to build the html of the form. My specific questions therefore have to do with the importance of those two modules. Are those modules simply used for the front end display of the form? Do the contents of the views of those modules have any bearing on the submission and post-submissions tasks of the form? If the answer is negative, this means I am not configuring the form correctly, so therefore, are there any resources to help solve that problem?
Here is my contact-form:index.js config file:
var async = require('async');
module.exports = {
extend: 'apostrophe-pieces',
name: 'contact-form',
label: 'Contact Form',
alias: 'contactForm',
addFields: [
{
name: 'name',
type: 'string',
label: 'First & Last Name',
required: true
},
{
name: 'company',
type: 'string',
label: 'Company Name',
required: true
},
{
name: 'email',
type: 'string',
label: 'Email Address',
required: true
},
{
name: 'phone',
type: 'string',
label: 'Phone Number & Extension',
required: true
},
{
name: 'subject',
type: 'string',
label: 'Subject',
required: true
},
{
name: 'message',
type: 'string',
label: 'Message',
textarea: true,
placeholder: "Don't be stupid"
}
],
permissionsFields: false,
afterConstruct: function(self) {
self.setSubmitSchema();
},
construct: function(self, options) {
self.setSubmitSchema = function() {
self.submitSchema = self.apos.schemas.subset(self.schema,
[ 'name', 'company', 'email', 'phone', 'subject', 'message' ]
);
};
self.submit = function(req, callback) {
var piece = {};
return async.series([
convert,
insert
], callback);
function convert(callback) {
return self.apos.schemas.convert(req, self.schema, 'form', req.body, piece, callback);
}
function insert(callback) {
return self.insert(req, piece, { permissions: false }, callback);
}
};
}
};
I'm the lead developer of Apostrophe at P'unk Avenue. We had some conversation in another forum but just for the record, there turned out to be two issues:
The form was submitting on any button click because that is what button elements do when they are of type "submit," and "submit" is the default value for type (at least in some browsers). It's not an Apostrophe issue and can be resolved by setting the type attribute as desired.
The form markup was custom and did not have wrapper elements such as data-name="title", etc. (corresponding to the schema) around the actual form field elements. You may use custom markup but all of the "moving parts" found in our official schemaMacros.html need to be there, i.e. the data attributes need to exist.
We do plan to make it easier to use custom markup without those wrappers, at least in cases where we can figure out which fields are which without them.
FYI, an element of type="file" will not work out of the box, but check out the attachment field type in apostrophe's schemas, which is pretty amazing for that role.

Google Contacts API learn is contact google+ or not

I'm using Google Contacts API to get user's contacts in my NodeJS app and I need to check, has contact google+ or not, but I can't find a way to do it in docs. Currently I'm receiving response from API that looks like this:
{ id: { '$t': 'http://www.google.com/m8/feeds/contacts/ex%40domain.com/base/40411dcf8aeb5354' },
updated: { '$t': '2016-08-12T08:03:22.026Z' },
category:
[ { scheme: 'http://schemas.google.com/g/2005#kind',
term: 'http://schemas.google.com/contact/2008#contact' } ],
title: { type: 'text', '$t': 'TestGoogleContact' },
link:
[ { rel: 'http://schemas.google.com/contacts/2008/rel#edit-photo',
type: 'image/*',
href: 'https://www.google.com/m8/feeds/photos/media/ii%40risingapp.com/40411dcf8aeb5354/1B2M2Y8AsgTpgAmY7PhCfg' },
{ rel: 'self',
type: 'application/atom+xml',
href: 'https://www.google.com/m8/feeds/contacts/ii%40risingapp.com/full/40411dcf8aeb5354' },
{ rel: 'edit',
type: 'application/atom+xml',
href: 'https://www.google.com/m8/feeds/contacts/ii%40risingapp.com/full/40411dcf8aeb5354/1470989002026004' } ],
'gd$email':
[ { address: 'testcontact#somedomain.com',
primary: 'true',
rel: 'http://schemas.google.com/g/2005#home' } ] }
Contacts API pre-dates Google+ so profile information is not available. A feature was added later to show just the G+ photo from the profile if a the user set one, which could be a hacky/flakey heuristic to check for a profile. However, you can easily get this information by using the People API instead, which joins G+ profile information onto contacts and will likely replace the Contacts API eventually: https://developers.google.com/people/

JayData - OData query gets "$data.Object not convertible to $data.ObjectID"

I've created an OData Endpoint with Node by using odata-server module by JayData in this way:
require("odata-server");
$data.Entity.extend("Service", {
Id: {type: "id", key: true, computed: true, nullable: false},
Name: {type: "string", nullable: false, maxLength: 50}
});
$data.EntityContext.extend("marketplace", {
Services: {type: $data.EntitySet, elementType: Service}
});
$data.createODataServer(marketplace, "/marketplace", 8081, "localhost");
console.log("Marketplace OData Endpoint created... Listening at 8081.");
Then, still with Node, I've created an Express web application which receives some commands through GET request, connects to the OData Endpoint (still by using JayData) and receives some data from there, then sends back the result to the client (in the following code it just sends 200), in this way (by defining a route):
require("jaydata");
...
app.get("/addCompare/:id", function(req, res) {
console.log("Comparison request for: " + req.params.id);
$data.Entity.extend("Service", {
Id: {type: "id", key: true, computed: true, nullable: false},
Name: {type: "string", nullable: false, maxLength: 50}
});
$data.EntityContext.extend("marketplace", {
Services: {type: $data.EntitySet, elementType: Service}
});
db = new marketplace("http://localhost:8081/marketplace");
db.onReady(function() {
var arr = db.Services.filter(function(s) {return s.Name.startsWith("Serv");}).toArray();
console.dir(arr);
});
res.send(200);
});
The problem is that when I try this code (by using this GET request for example: http://www.localhost:8080/addCompare/NTM0M2ZkNjU2YjljNWMwODRiOGYyYTU5), I always get this error in the server and after that it crashes. Here's the error:
TypeError: Value '$data.Object' not convertable to '$data.ObjectID'
{ name: 'TypeError',
message: 'Value \'$data.Object\' not convertable to \'$data.ObjectID\'',
data:
{ __metadata:
{ type: 'Service',
id: 'http://localhost:8081/marketplace/Services(\'NTM0M2ZkNjU2YjljNWMwODRiOGYyYTU5\')',
uri: 'http://localhost:8081/marketplace/Services(\'NTM0M2ZkNjU2YjljNWMwODRiOGYyYTU5\')' },
Id: 'NTM0M2ZkNjU2YjljNWMwODRiOGYyYTU5',
Name: 'Service51' } }
Where am I wrong? Thanks...
As the behavior was explained in OData - Strange index with MongoDB [Mongoose: Cast Error], the id - NTM0M2ZkNjU2YjljNWMwODRiOGYyYTU5 – should be base-64 decoded (for example 5343fd656b9c5c084b8f2a70 is a valid format).
Although the declaration of JayData model is correct, it will be re-defined every single time when a request arrives to your server. You can improve the current implementation by moving your $data.Entity.extend and $data.EntityContext.extend blocks outside the app.get – after require("jaydata");.

Resources