Custom auth (OAuth2) for Parse-server on docker container - javascript

So, as the title suggests, I'm looking for a way to integrate my own custom authentication service into the parse server, which is installed inside a docker container. This authentication is basically an OpenID implementation of KeyCloak.
The point is that I don't (and it would be best for my architecture not to) have parse server served with express on my local machine.
What I've been trying so far, was to search the internet, read the issues, read the parse server documents for JavaScript and the guide and other stuff to find out, how can I achieve it.
It seems that it doesn't matter what I do, at the end of each test, I get a 252 This authentication method is unsupported error! (this happens even if I use facebook, oauth, oauth2, etc).
So right now, the docker-compose service looks like this:
parse-server:
image: parseplatform/parse-server
ports:
- "${SERVER_PORT}:1337"
restart: "always"
volumes:
- ./server/parse/custom-auth:/parse-server/custom-auth
depends_on:
- mongodb
links:
- mongodb:mongo
environment:
- PARSE_SERVER_APPLICATION_ID=${APP_ID}
- PARSE_SERVER_MASTER_KEY=${MASTER_KEY}
- PARSE_SERVER_DATABASE_URI=mongodb://mongo:${MONGO_PORT}/dev
- PARSE_SERVER_START_LIVE_QUERY_SERVER=1
- PARSE_SERVER_LIVE_QUERY={"classNames":${LIVE_QUERY_CLASSES}}
- PARSE_SERVER_MOUNT_GRAPHQL=${GQL_API}
- PARSE_SERVER_MOUNT_PLAYGROUND=${GQL_PLAYGROUND}
- PARSE_SERVER_AUTH_PROVIDERS={"swwwan-mail-auth":{"module":"/parse-server/custom-auth/swwwan-mail-auth/index.js"}}
and the login/signup part:
export const loginWithParse = async (account: IUserColumnTypes) => {
if (account.username === null || account.password === null) {
throw "validation failed";
}
// #ts-ignore
const loggedIn = await Parse.User.logInWith("swwwan.mail-auth", {
authData: {
id: "",
access_token: "",
},
});
console.log({ loggedIn });
//return await Parse.User.logIn(account.username, account.password);
};
another alternative for login/signup:
export const loginWithParse = async (account: IUserColumnTypes) => {
if (account.username === null || account.password === null) {
throw "validation failed";
}
const u = new Parse.User();
u._linkWith("swwwan-mail-auth", {
authData: {
id: "tester",
access_token: "sample_access_token",
},
})
.then(res => console.log(res))
.catch(e => console.log(e));
//return await Parse.User.logIn(account.username, account.password);
};
UPDATE: by using the second alternative, I actually get the error:
error: Parse error: Invalid key name: authData.swwwan-mail-auth.id {"code":105,"stack":"Error: Invalid key name: authData.swwwan-mail-auth.id
Is there a way to make it work? probably I'm missing something here.
tnx :)

note that the 'dangle' in the link functions will be deprecated in the forthcoming 2.9 release of the Parse JS SDK
Sorry that the documentation isn't better yet. Will be getting some more work
What you're attempting is doable!
Your final error is giving one big clue: the name of your adapter can't have any characters that aren't valid for a javascript identifier. In this case, the - is causing a problem since when we save it in the database, the adapter name is used as a key.
The unit tests are often the best documentation and you may find them helpful in this case.
See:
the declaration of a custom adapter
Configuring the server to load the adapter (you're doing this right)
using the adapter

Related

AuthRetryableFetchError: self signed certificate in certificate chain with Supabase and Next.js

I'm receiving the following error with certificates when trying to fetch the user from Supabase inside getServerSideProps with Next.js:
AuthRetryableFetchError: request to https://[redacted].supabase.co/auth/v1/user failed, reason: self signed certificate in certificate chain
at [redacted]/node_modules/#supabase/gotrue-js/dist/main/lib/fetch.js:30:16
This is a simplified version of my code for reference:
export const getServerSideProps = async ({ req, res }) => {
const supabase = createServerSupabaseClient({ req, res });
const { data: { user }, error } = await supabase.auth.getUser();
if (error) console.error(error);
return {
props: {
user,
}
}
};
I've already setup yarn and npm to both use the right certificate using yarn config set cafile /path/to/certificate/file and npm config set cafile /path/to/certificate/file respectively, but for some reason when Next.js tries to get this from the server side (Node.js) it fails, and I'm not sure what service I need to setup to tell it where the certificate is set?
There are a lot of similar questions out there, but I couldn't find any specifically about Next.js or hitting this issue in Node.js.
Any help appreciated.
So it seems to be possible to get round this issue with setting NODE_TLS_REJECT_UNAUTHORIZED=0 in env.local, but if anyone knows how to fix the issue rather than avoid it I'd be interested still.
src: https://stackoverflow.com/a/45088585/827129

Nodejs mssql/msnodesqlv8 issue sending semicolon in database request

Attempting to build a basic API to interact with a MSSQL v12 database using Nodejs. I have been able to connect to the database using the mssql/msnodesqlv8 package but parameterized queries are failing with the following.
code: 'EREQUEST',
number: 102,
state: undefined,
originalError:
{ Error: [Microsoft][SQL Server Native Client 11.0][SQL Server]Incorrect syntax near ''. sqlstate: '42000', code: 102 },
name: 'RequestError' }
Debug: internal, implementation, error
I used SQL Server Profiler and saw that the query was coming in as such
exec sp_executesql N'declare #SecurityKey nvarchar (MAX);set #SecurityKey=#P1;exec database.getSecurityBySecurityId #SecurityKey;',N'#P1 nvarchar(20)',N'XXXXXXXX'
and failing. After some investigation it seems to be an issue with the semicolons after the declare and set statements as it is not allowed in TSQL (very new to MSSql, will need to read up). Removing the semicolons did indeed fix the issue when I ran the query manually.
So my question is this.. is there a way to get msnodesqlv8 to work with my version on |Mssql and if yes, how so? Is there a way to omit these semicolons.
If you think there is a better way, i would like to hear it as I am new to Nodejs + MSSql.
Contents of getSecurity.sql
exec database.getSecurityBySecurityId #SecurityKey
contents of index.js
"use strict";
const utils = require("../utils");
const api = async ({ sql, getConnection }) => {
const sqlQueries = await utils.loadSqlQueries("events");
const getSecurity = async SecurityKey => {
const cnx = await getConnection();
const request = await cnx.request();
request.input('SecurityKey', SecurityKey);
return request.query(sqlQueries.getSecurity);
};
return {
getSecurity
};
};
module.exports = { api };
I was able to work around this by editing the library.
In ./lib/msnodesqlv8.js you can find where is concatenates the query string
...
}
if (input.length) command = `declare ${input.join(',')} ${sets.join(';')};${command};`
if (output.length) {
command += `select ${output.join(',')};`
handleOutput = true
}
....
Editing this will allow you to control the flow.

How do I authenticate against GitHub using an API key?

I am trying to use the GitHub Javascript API but am unable to authenticate using my API key. The API Docs say I can use:
{
username: 'my-username',
password: 'my-password'
// , token: 'or an optional oAuth token'
}
But I'd like to use my API Key instead, much like I can do with curl from the command line. (for example)
curl --user "$user:$api_key" --include --request DELETE "https://api.github.com/repos/$user/$repo/labels/enhancement"
I've tried using my API Key as the token but that doesn't work.
Is use of the API Key to access GitHub via the Github API wrapper not supported? That would be weird.
Okay so it turns out what I was calling my API Key is the same thing as the personal access token and I was just being confused because
import GitHub from 'github-api'
const gh = new GitHub({
token: 'MY-PERSONAL-ACCESS-TOKEN-OBTAINED-FROM-github.com/settings/tokens' // real token redacted obviously
})
const me = gh.getUser()
console.log('me', me)
was spitting out
me User {
__apiBase: 'https://api.github.com',
__auth:
{ token: '970818535b841883ff2735fe127d289032970389',
username: undefined,
password: undefined },
__AcceptHeader: 'v3',
__authorizationHeader: 'token MY-PERSONAL-ACCESS-TOKEN-OBTAINED-FROM-github.com/settings/tokens',
__user: undefined }
and I was interpreting __user: undefined to mean that the authentication was not working.
However if I actually try then adding
me.listNotifications().then(
notifications => console.log('notifications', notifications),
err => console.log('error', err)
).catch(err => console.log('fatal', err))
tadah it works.
If I throw in a rubbish token new GitHub doesn't complain (because presumably it's not actually going off to GitHub to do the auth at that point as I first thought), but the .listNotifications() does get rejected with a 401 error.
So, that's resolved my confusion.

CF Connect to the cloud controller

I use the following lib to connect to the cloud controller
https://github.com/prosociallearnEU/cf-nodejs-client
const endpoint = "https://api.mycompany.com/";
const username = "myuser";
const password = "mypass";
const CloudController = new (require("cf-client")).CloudController(endpoint);
const UsersUAA = new (require("cf-client")).UsersUAA;
const Apps = new (require("cf-client")).Apps(endpoint);
CloudController.getInfo().then((result) => {
UsersUAA.setEndPoint(result.authorization_endpoint);
return UsersUAA.login(username, password);
}).then((result) => {
Apps.setToken(result);
return Apps.getApps();
}).then((result) => {
console.log(result);
}).catch((reason) => {
console.error("Error: " + reason);
});
I try to run it against our API and its not working and Im not getting no error message in the console, what it can be ?
where does the space/org is handled here ? since when I connect from the cli it ask me to which space/org I want to connect...
Im able to login via the CLI, just from the code I cant, any idea what is missing here?
The issue it when I run it I dont get any error that can help to understand what is the root cause
I cloned the original git repository and modified some methods to support proxy. Please note that I modified just some methods to get the sample code working, but a complete refactor of the package is needed.
Basically what you have to do is to add a proxy parameter before calling the request method (this is done throughout the package, so several modifications are needed), for example this is for one of the methods in the Organization.js file:
getSummary (guid) {
const url = `${this.API_URL}/v2/organizations/${guid}/summary`;
const proxy = `${this.API_PROXY}`;
const options = {
method: "GET",
url: url,
proxy: proxy,
headers: {
Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}`
}
};
return this.REST.request(options, this.HttpStatus.OK, true);
}
You can find my changes in the git repository below:
https://github.com/adasilva70/cf-nodejs-client.git
I have also created a new sample below. This sample lists all organizations for a user, gets the first organization returned and lists its spaces. You can modify the code to provide a similar functionality that cf login provides (allow you to select an organization then a space).
const endpoint = "https://api.mycompany.com/";
const username = "youruser";
const password = "yourpassword";
const proxy = "http://proxy.mycompany.com:8080";
const CloudController = new (require("cf-nodejs-client")).CloudController(endpoint, proxy);
const UsersUAA = new (require("cf-nodejs-client")).UsersUAA;
const Apps = new (require("cf-nodejs-client")).Apps(endpoint, proxy);
const Orgs = new (require("cf-nodejs-client")).Organizations(endpoint, proxy);
CloudController.getInfo().then((result) => {
console.log(result);
UsersUAA.setEndPoint(result.authorization_endpoint, proxy);
return UsersUAA.login(username, password);
}).then((result) => {
//Apps.setToken(result);
//return Apps.getApps();
Orgs.setToken(result);
return Orgs.getOrganizations();
}).then((result) => {
console.log(result);
org_guid = result.resources[1].metadata.guid;
return Orgs.getSummary(org_guid);
}).then((result) => {
console.log(result);
}).catch((reason) => {
console.error("Error: " + reason);
});
I have done just minor tests to make sure the sample works, so use carefully. Also, the changes will only work for a case where proxy is needed now.
The first thing that strikes me on the library's github site is the warning:
Note: This package is not ready for a production App yet.
It also seems that the project is not being maintained as there are a number of tickets ooened that are quite a few months old that don't have a response.
Anyway, to figure out why the library is not working and producing no error message, I would check out the library source code and add some console logging statements, probably starting with the HttpUtils. For example:
requestWithDefaults(options, function (error, response, body) {
console.log("requestWithDefaults error: ", error)
console.log("requestWithDefaults response: ", response)
console.log("requestWithDefaults body: ", body)
...
}
Alternatively, you could try debugging the code by adding breakpoints to the requestWithDefaults and other key places in the library, using the nodejs debugger.
You could also try debugging the network calls similar to this how to monitor the network on node.js similar to chrome/firefox developer tools?
To understand how to use the library, I would take a look into the tests folder and look for a test that is similar to your use case. There are a reasonable amount if tests that look useful in the test/lib/model/cloudcontroller folder.
As for the question about spaces, I have found an example where you can pass in a space guid to return apps for that space guid.
CloudFoundrySpaces.getSpaceApps(space_guid, filter).then( ... )
I'm assuming the call you are using App.getApps() will return Apps for all spaces/organizations.

Using Breeze.js EntityManager from within Node

I'm interested in being able to use the Breeze.js EntityManager and query capabilities within a node console service to access a remote Data Service that exposes an BreezeJS/OData compliant RESTful endpoint.
We currently have a Data Service implemented using Node.js, MongoDB and the Breeze.js breeze-mongodb module.
We have web browser hosted clients that access the MondgoDB using the Breeze.js client API (EntityManager) and the Data Service described above.
I need to create another Node.js service that can access the same MongoDB database that the web browser hosted clients do, and for consistency/simplicity I would like to use the same data acceess API as I am using in the web browser.
Has anyone experimented with this configuration?
I experimented with loading Breeze and its dependencies using the Node.js module infrastructure, but am getting errors when Breeze tries to initialize Angular as an ajax handler. Angular is installed and configured as a node module dependency, but I am getting an error thrown:
Error: [$injector:nomod] http://errors.angularjs.org/1.2.2/$injector/nomod?p0=ngLocale
In theory I shouldn't need angular, but I get additional errors if Angular is not present.
I may be able to debug this particular issue, but it will require stepping through Breeze.js code in detail and possibly modifying it to fix. Was curious if anyone else has gotten this working.
I'm running Breeze in Node at the moment. It used to work just fine without any modification, but a few versions ago they added a check that it's running in the browser... so now I manually remove that check :-)
My use-case is a little bit different: I'm running breeze on the server so that I can use the same business logic as in the client, and just have a really really thin layer between breezejs and the DB.
The only thing I needed to change to get it to run in the browser is add a fake ajax handler that delegates to my skinny DB wrapper - you could equally delegate to anything else, including your existing API.
var ctor = function () {
this.name = 'node';
this.defaultSettings = { };
};
ctor.prototype.initialize = function () {
};
var query = require('../../../../server/db/query');
ctor.prototype.ajax = function (config) {
if (config.url === '/api/all') {
query.get()
.then(function (result) {
var httpResponse = {
data: result,
status: '400',
getHeaders: undefined,
config: config
};
config.success(httpResponse);
})
.otherwise(function (error) {
var httpResponse = {
data: '',
status: '500',
getHeaders: undefined,
error: error,
config: config
};
config.error(httpResponse);
});
} else if (config.url === '/api/SaveChanges') {
query.save(JSON.parse(config.data))
.then(function (result) {
var httpResponse = {
data: result,
status: '400',
getHeaders: undefined,
config: config
};
config.success(httpResponse);
})
.otherwise(function (error) {
var httpResponse = {
data: '',
status: '500',
getHeaders: undefined,
error: error,
config: config
};
config.error(httpResponse);
});
}
};
breezejs.config.registerAdapter('ajax', ctor);
breezejs.config.initializeAdapterInstance('ajax', 'node', true);
It's a good question. We haven't actually tried running Breeze within Node but your use case is interesting. This sounds like a perfect item for the Breeze User Voice. We take these suggestions seriously.

Categories

Resources