Does Feathers Authentication also require app internal service calls to be authenticated (and how to get around)? - express

I'm building a FeathersJS service behind an authentication very similar to the messages service that is part of the FeathersJS demo chat app: https://github.com/feathersjs/feathers-chat/
Additionally, I'd like to define an event listener that should store the messages it receives to the app's messages service and call all necessary hooks to notify the client application.
Here's my current approach:
module.exports = function () {
const app = this;
const Model = createModel(app);
const paginate = app.get('paginate');
const options = {
name: 'messages',
Model,
paginate
};
app.use('/messages', createService(options));
const service = app.service('messages');
service.hooks(hooks);
const sender = new MyExternalMessageSender();
sender.on('message', (msg) => {
service.create(msg, {user: {_id: 0}}).then(result => console.log(result));
});
if (service.filter) {
service.filter(filters);
}
};
This sometimes works fine and sometimes it randomly results in an error as soon as MyExternalMessageSender is notified and tries to call the message service's create method.
NotAuthenticated: No auth token
at Error.NotAuthenticated (projects\feathers-chat\node_modules\feathers-errors\lib\index.js:100:17)
at projects\feathers-chat\node_modules\feathers-authentication\lib\hooks\authenticate.js:102:31
How can I store messages the correct way without my application itself needing to use a JWT?
Thanks for your support!

I am not sure what MyExternalMessageSender does but authentication is skipped by default in internal service calls. If it is an internal service call is determined by params.provider being set. So if you pass hook.params from an external call (where provider is normally set to rest or socketio) to subsequent service calls authentication will run (since it thinks it is an external call).
This can be avoided by removing the provider property before passing the original parameters e.g. with Lodash _.omit:
myservice.find(_.omit(params, 'provider'))

Related

Accessing session store in service functions

I try to create pure functions or at least some service classes for accessing backend apis with typed methods. For authentication I use cookies.
For client requests cookie authentication works on the fly, but for ssr I have to add a cookie header as part of the request while using fetch.
I have the required token already in the session, but if I try to access to the session via import { session } from '$app/stores'; outside of a component, I got
Function called outside component initialization.
One option could be to add on each SSR api function call the cookie header manually as parameter, but this won't seam to be a clean way.
Does someone have an idea on how access the session outside of a component, or are there any possible ways to define service classes containing access to stores (incl. session store) which's functions are usable across components?
I would like to use something like:
export async function load({ page, fetch, session, context }) {
let me = (await service.getLoggedInUser())?.username ?? "not logged in";
// or:
me = (await getLoggedInUser())?.username ?? "not logged in";
// ...
}
Instead of:
export async function load({ page, fetch, session, context }) {
let me = (await service.getLoggedInUser(session))?.username ?? "not logged in";
// or:
me = (await getLoggedInUser(session)())?.username ?? "not logged in";
// ...
}
Would be great if someone can provide a hint to continue.
Thank you in advance.
Ramazan

How to set up Relay Modern with a Promise-based Environment? (e.g. Auth0 or another async authentication service?)

In Relay Classic, we would just pass a function to react-relay-network-layer to return the required token in a promise. What's the equivalent in Relay Modern?
Ideally I'd like to display the Loading screen until the Environment promise resolves, and then display the main Component once we have an Environment and the query is fetched.
So if I knew how to swap out QueryRenderer's environment, that would also solve the issue.
The recommended method here is to fetch the authentication token inside of fetchQuery.
The remaining challenge is how to make sure the async authentication function is called only once, even if Relay fetches multiple times while authentication is still ongoing. We did this using a singleton promise; each call to fetchQuery calls the static Promise.resolve() method on the same promise, so that once the authentication call finishes, all fetchQuery calls continue with the desired authentication information.
So fetchQuery gets an auth token (JWT) with:
const authToken = await AuthToken.get();
And AuthToken looks like (TypeScript):
class AuthToken {
private static _accessTokenPromise: Promise<string>;
public static async get() {
if (!this._accessTokenPromise)
this._accessTokenPromise = this.AuthFunction(); // AuthFunction returns a promise
return await Promise.resolve(this._accessTokenPromise);
}
}

Ember authentication with Oauth server/client

I am trying to design the authentication flow of an Ember application with a Rails backend. I basically want to authenticate users via Google/Facebook/etc., I do not want to provide an 'independent' authentication service. I do want to maintain a list of users of course on the server side, potentially merging different authentications from different sources into the same user. I will not interact on behalf of the user on Google/Facebook from the client side, but I will do that on the server side.
For the above reason I was planning to do the following:
I will use torii to fetch an auth_token on the client side and I will pass that onto the server side, where I will validate it, convert it into an access token.
I will generate a custom token on the server side which I will send back to the client and require all further API calls to be accompanied by that token. I will not share the access token with the client at all.
Would you say that this is an optimal flow?
In terms of implementation, I have been able to get auth_tokens from the different providers using the example here. I am completely unsure however:
if I need ember-simple-auth or only torii (how do these two complement each other?)
how do I pass the auth token to the server side? With the code below I can get the auth token, but is this the proper place to implement the call to the API?
export default Ember.Route.extend({
actions: {
googleLogin: function() {
var _this = this;
this.get('session').authenticate('simple-auth-authenticator:torii', 'google-oauth2').then(
function() {console.log(_this.get('session.secure.authorizationCode'));}
);
return;
},
facebookLogin: function() {
this.get('session').authenticate('simple-auth-authenticator:torii', 'facebook-oauth2');
return;
}
}
});
how do I make all further requests to the API to be accompanied by a specific token?
should I use devise on the server side to make it easier or not?
I have been implemented exactly the same kind of workflow.
I used ember-simple-auth with ember-simple-auth-torii and implemented a custom authenticator to achieve this goal.
Ember-simple-auth provides an example of a custom authenticator here .
Your custom authenticator implementation will look like the following
First get auth_token using torii
Then valid this auth_token against your backend in order to get your custom token
Your authenticate callback in your custom authenticator will basically look like the following :
authenticate: function(provider, options) {
var self = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
self.torii.open(provider, options || {}).then(function(data) {
var endpoint = '/token'; // Your API endpoint used to get your cutom token
var dataToSend = { // Data sent to your endpoint
grant_type: 'authorization_code',
code: data.accessToken,
access_token: data.accessToken
};
$.post(endpoint, dataToSend).done(function(response) {
response.provider = provider;
resolve(data);
}).fail(function(response) {
response.provider = provider;
reject(data);
})
}, reject)
})
}
Once you have the custom authenticator initilized you can use it this way on your controllers :
this.get('session').authenticate(
'authenticator:customauthenticator', // Or wathever name you gave
'facebook-connect' // Any compatible torii provider
).then(function(user) {
console.log(user); // Will display ajax response from your endpoint
})
Finally, if you want your custom token to be automatically sent with all ajax request, you can use the ember-simple-auth oauth2-bearer authorizer.

How to call an express.js handler from another handler

I'm building an isomorphic React application which is using express.js on the server. The client app makes a number of AJAX requests to other express handler which currently entails them making multiple HTTP requests to itself.
As an optimisation I'd like to intercept requests I know the server handles and call them directly (thus avoiding the cost of leaving the application bounds). I've got as far as accessing the apps router to know which routes it handlers however I'm struggling to find the best way to start a new request. So my question is:
How do I get express to handle an HTTP request that comes from a programatic source rather than the network?
I would suggest create a common service and require it in both the handlers. What I do is break the business logic in the service and create controllers which handles the request and call specific services in this way u can use multiple services in same controller eg.
router.js
var clientController = require('../controllers/client-controller.js');
module.exports = function(router) {
router.get('/clients', clientController.getAll);
};
client-controller.js
var clientService = require('../services/client-service.js');
function getAll(req, res) {
clientService.getAll().then(function(data) {
res.json(data);
}, function(err) {
res.json(err);
});
}
module.exports.getAll = getAll;
client-service.js
function getAll() {
// implementation
}
module.exports.getAll = getAll;
u can also use something like http://visionmedia.github.io/superagent/ to make http calls from controllers and make use of them.

ember simple auth session, ember data, and passing a Authorization header

I have a working oauth2 authentication process where I get an access token (eg from facebook) using ember simple auth, send it to the back end which calls fb.me() and then uses JWT to create a token. This token is then sent back to the ember app, which then has to send it with every server request, include those requests made by ember-data.
I also need to have this token available after a browser reload.
I have tried many options, where I set a property 'authToken' on the session - I believe that this uses local storage to persist the authenticated session.
But I always seem to have trouble with coordinating the retrieval of this token - either I don't have access to the session, or the token is no longer on the session, or I can't change the ember data headers.
Does anyone have a working simple example of how this can be done - I think it should be easy, but I'm obviously missing something!
Thanks.
Update
The only thing I've been able to get working is to use torii as shown below, but the session content is still lost on refresh - I can see its still authenticated, but its lost the token I set here. So I'm still looking for a real solution.
authenticateWithGooglePlus: function () {
var self = this;
this.get('session').authenticate('simple-auth-authenticator:torii', 'google-oauth2')
.then(function () {
resolveCodeToToken(self.get('session'), self);
});
}
resolveCodeToToken gets the bearer token from the server, sets it on the session and then transitions to the protected page:
function resolveCodeToToken(session, route) {
var authCode = session.content.authorizationCode;
var type = session.content.provider.split('-')[0];
$.ajax({
url: 'http://localhost:4200/api/1/user/auth/' + type,
data: {authCode: authCode}
}).done(function (response) {
// todo handle invalid cases - where user is denied access eg user is disabled
session.set('authToken', response.token);
route.transitionTo('activity', moment().format('DDMMYYYY'));
});
}
And I have a custom authorizer for putting the token (stored in the session) on every request:
import Base from 'simple-auth/authorizers/base';
export default Base.extend({
authorize: function(jqXHR, requestOptions) {
var accessToken = this.get('session.content.authToken');
if (this.get('session.isAuthenticated') && !Ember.isEmpty(accessToken)) {
jqXHR.setRequestHeader('Authorization', accessToken);
}
}
});
I'm not sure why this.get('session.content.authToken') would be undefined after a refresh, I thought by default the session was persisted in local storage. The fact that it is authenticated is persisted, but thats useless without the token since the server will reject calls to protected endpoints.
You'd want to implement your own custom authenticator that first gets a token from Facebook and then sends that to your own server to exchange it for a token for your app. Once you have that you get authorization of ember-data requests as well as session persistence etc. for free.
Have a look at this example: https://github.com/simplabs/ember-simple-auth/blob/master/examples/7-multiple-external-providers.html