Standalone alternative to express-session for use in serverless context (w/ DynamoDB) - express

Background: why use cookies with Lambdas?
OWASP is very clear that cookies are the best option for session management:
.. cookies .. are one of the most extensively used session ID exchange mechanisms, offering advanced capabilities not available in other methods.
However AWS's API Gateway literature often talks about using JWTs for authentication rather than cookies. While some tech blogs out there seem to think it's ok to use JWTs in this way, there are definitely recognised issues with JWTs. Two issues of particaular note are:
(a) you can't easily invalidate a JWT. At best you can keep a server-side database of blocked JWTs and make sure any service validating JWTs also implements a check against this block list. That sounds a lot like implementing regular old sessions, largely defeating the point of using JWTs.
(b) if your want to use JWTs for authorization as well as authentication, you'll run into issues when you need to update the authorization and it's not a change being driven by the enduser themselves. Scenarios in this category include: a system administrator or account manager changes the user's access level; a trial/contract is ended by a cron job; a webhook is triggered by a 3rd party SaaS integration (e.g. Stripe). You might say, "in that case use a separate mechanism for authorization", but then again you're back to good old sessions.
To be clear, I understand the value of JWTs in letting one server communicate its trust in a user's identity to another server, but that's a very different purpose to session management.
Session management in Node
All roads seem to lead to express-session as the most battle-tested implementation of sessions in Node. It offers a wide range of storage options to choose from*.
In the context of Lambdas, in principle you could try and use express-session as though it were just a function factory, for functions with the signature (req,res,next)=>void, that's rather hacky, and in no way recommended by express-sessions. It's also not entirely clear how best to match that call signature to the objects you get in an AWS Lambda, nor which storage mechanisms are optimised for lambdas (which are ephemeral and need to start quickly).
I would really like a lightweight node module that lets you do something like the following:
import {Sessions} from 'sessions';
// configure session management. Should be super lightweight for use in Lambda.
const sessions = new Sessions({
/* ..basic cookie & expiration config, */
secret: "something", // extra security recommended by express
store: { // object with following interface:
createSession(sessionId, metadata),
getFromSessionId(sessionId),
updateSession(sessionId, metadata),
customIndexedProperties: ['userId'], // in addition to sessionId
getSessionIdsFromIndexedProperty(propertyName, propertyValue),
}
});
// create session. Note the api is not opinionated about response header mechanics.
response.headers['set-cookie'] = await sessions.createCookieForSession({
userId: 'user1',
/*...other user info */
});
// get user's session. Again not opinionated about where cookie comes from.
const userSessionInfo = await sessions.getSessionFromCookie(request.header['cookies']);
// update a user's session, but not initiated by the user themselves
const sessionIds = await sessions.getSessionIdsFromIndexedProperty('userId', 'user1');
await sessions.updateSession(sessionIds[0], {something: 'has change'});
Questions
Is my above thinking reasonable?
Are there any node packages I've not encountered that might be helpful.
If not, why not? I have come across a few people with closely related problems, but it must be a fairly common issue when working with serverless.
If I were to implement a module to my own liking how do I get any confidence that I've done a good job security-wise? I could use pieces of express-session that are relevant, but that's not a great long-term solution for good security.
Related to 4, if I were to try and hook into express-sessions, but just build my own store that does what I need, how would I get confidence in the security? Also, I haven't managed to find any docs on what the official api is for an express-session store, which I find amazing given that express-sessions seems to be the go to for sessions in Node.
Any help would be massively appreciated, thanks!
P.S. I appreciate a lot of what I'm discussing relates to open source projects that are often poorly funded. However, I was very surprised to have reached the above conclusions about the state of the ecosystem and wondered if I was missing something.
*Annoyingly, the suggested DynamoDb store package isn't great. Two of the features we'd want from it are not support, indeed PRs seem to have been opened back in 2019 but never looked at by the maintainer. Technically we don't absolutely have to use DynamoDb as our store, but it is does offer a lot of features we like.

Related

Make Strawberry Shake request from Blazor with or without credentials

In my Blazor app (which uses Azure B2C), I want to be able to call an endpoint whether the user is authenticated or not.
I've searched quite a bit, and everything I find says I should create two HttpClients (example), one for anonymous and one for authenticated, or use IHttpClientFactory with named clients.
The problem is I am using Strawberry Shake which only allows me to configure HttpClient once (it is using a named client and IHttpClientFactory internally).
Their documentation gives a simple example of setting authentication:
services
.AddConferenceClient()
.ConfigureHttpClient((serviceProvider, client) =>
{
var token = serviceProvider.GetRequiredService<ISomeService>().Token;
});
I thought I could use this to conditionally select which handler(s) I wanted, but the only ways I can find to get the token (IAccessTokenProvider.RequestAccessToken()) or validate authentication (Task<AuthenticationState>) require async calls, which are not allowed in this context. Even .Result doesn't work (not that I wanted to use it anyway).
My last thought is that maybe I could accomplish this by inheriting from BaseAddressAuthorizationMessageHandler or chaining handlers, but I can't figure out how. I even tried copying the source code and modifying it, but still couldn't get it to work (UPDATE: Actually, that did work, but it still seems less than ideal).
So many approaches seem workable, but ultimately fail me. How can I get this to work? Please provide code example if possible.

How to organize endpoints when using FeathersJS's seemingly restrictive api methods?

I'm trying to figure out if FeathersJS suits my needs. I have looked at several examples and use cases. FeathersJS uses a set of request methods : find, get, create, update, patch and delete. No other methods let alone custom methods can be implemented and used, as confirmed on this other SO post..
Let's imagine this application where users can save their app settings. Careless of following method conventions, I would create an endpoint describing the action that is performed by the user. In this case, we could have, for instance: /saveSettings. Knowing there won't be any setting-finding, -creation, -updating (only some -patching) or -deleting. I might also need a /getSettings route.
My question is: can every action be reduced down to these request methods? To me, these actions are strongly bound to a specific collection/model. Sometimes, we need to create actions that are not bound to a single collection and could potentially interact with more than one collection/model.
For this example, I'm guessing it would be translated in FeathersJS with a service named Setting which would hold two methods: get() and a patch().
If that is the correct approach, it looks to me as if this solution is more server-oriented than client-oriented in the sense that we have to know, client-side, what underlying collection is going to get changed or affected. It feels like we are losing some level of freedom by not having some kind of routing between endpoints and services (like we have in vanilla ExpressJS).
Here's another example: I have a game character that can skill-up. When the user decides to skill-up a particular skill, a request is sent to the server. This endpoint can look like POST: /skillUp What would it be in FeathersJS? by implementing SkillUpService#create?
I hope you get the issue I'm trying to highlight here. Do you have some ideas to share or recommendations on how to organize the API in this particular framework?
I'm not an expert of featherJs, but if you build your database and models with a good logic,
these methods are all you need :
for the settings example, saveSettings corresponds to setting.patch({options}) so to the route settings/:id?options (method PATCH) since the user already has some default settings (created whith the user). getSetting would correspond to setting.find(query)
To create the user AND the settings, I guess you have a method to call setting.create({defaultOptions}) when the user CREATE route is called. This would be the right way.
for the skillUp route, depends on the conception of your database, but I guess it would be something like a table that gives you the level/skills/character, so you need a service for this specific table and to call skillLevel.patch({character, level})
In addition to the correct answer that #gui3 has already given, it is probably worth pointing out that Feathers is intentionally restricting in order to help you create RESTful APIs which focus on resources (data) and a known set of methods you can execute on them.
Aside from the answer you linked, this is also explained in more detail in the FAQ and an introduction to REST API design and why Feathers does what it does can be found in this article: Design patterns for modern web APIs. These are best practises that helped scale the internet (specifically the HTTP protocol) to what it is today and can work really well for creating APIs. If you still want to use the routes you are suggesting (which a not RESTful) then Feathers is not the right tool for the job.
One strategy you may want to consider is using a request parameter in a POST body such as { "action": "type" } and use a switch statement to conditionally perform the desired action. An example of this strategy is discussed in this tutorial.

How to keep GraphQL API and frontend synchronized on a staging server?

We have a Rails application with GraphQL API in one GIT repository, and React frontend application in another. Both backend and frontend have CI and are deployed separately. But both backend and frontend are still under heavy development and often our staging server doesn't work, because deployment is not synchronized and we don't test the whole application - we test API and we test frontend without API.
What is the best way to deploy frontend and backend only when they are synchronized, I mean when new versions doesn't break functionalities? I thought about third repository with backend and frontend included as GIT modules, acceptance tests and deploying both sides at once. But maybe there is simpler solution? Maybe some versioning?
You certainly can do versioning with GraphQL, but ideally any changes to your schema shouldn't be breaking ones. This just takes discipline on the part of your backend devs, although there are also tools (like this) to help detect breaking changes. Some general guidelines:
Deprecate fields using the #deprecated directive instead of deleting them. Deprecated fields can be communicated to client teams and retired after some agreed-upon amount of time.
Avoid renaming types. Try to use more specific naming to avoid having to rename things in the future (i.e. use emailMessage instead of just message if you could foreseeably have a different kind of message in the future).
Use payload types for mutations. If you mutate a User, for example, instead of just returning the User, return a payload type that has a user field. If down the road, you realize the mutation should also return other information, you can easily add fields to the payload type without creating breaking changes.

How do multiple versions of a REST API share the same data model?

There is a ton of documentation on academic theory and best practices on how to manage versioning for RESTful Web Services, however I have not seen much discussion on how multiple REST APIs interact with data.
I'd like to see various architectural strategies or documentation on how to handle hosting multiple versions of your app that rely on the same data pool.
For instance, suppose you make a database level destructive change to a database table that causes you to have to increment your major API version to v2.
Now at any given time, users could be interacting with the v1 web service and the v2 web service at the same time and creating data that is visible and editable by both services. How should this be handled?
Most of changes introduced to API affect the content of the response, till changes introduced are incremental this is not a very big problem (note: you should never expose the exact DB model directly to the clients).
When you make a destructive/significant change to DB model and new API version of API is introduced, there are two options:
Turn the previous version off, filter out all queries to reply with 301 and new location.
If 1. is impossible to need to maintain both previous and current version of the API. Since this might time and money consuming it should be done only for some time and finally previous version should be turned off.
What with DB model? When two versions of API are active at the same time I'd try to keep the DB model as consistent as possible - having in mind that running two versions at the same time is just temporary. But as I wrote earlier, DB model should never be exposed directly to the clients - this may help you to avoid a lot of problems.
I have given this a little thought...
One solution may be this:
Just because the v1 API should not change, it doesn't mean the underlying implementation cannot change. You can modify the v1 implementation code to set a default value, omit the saving of a field, return an unchecked exception, or do some kind of computational logic that helps the v1 API to be compatible with the shared datasource. Then, implement a better, cleaner, more idealistic implementation in v2.
when you are going to change any thing in your API structure that can change the response, you most increase you'r API Version.
for example you have this request and response:
request post: a, b, c, d
res: {a,b,c+d}
and your are going to add 'e' in your response fetched from database.
if you don't have any change based on 'e' in current client versions, you can add it on your current API version.
but if you'r new changes are going to change last responses, for example:
res: {a+e, b, c+d}
you most increase API number to prevent crashing.
changing in the request input's are the same.

Backbone.sync – Collection using ajax as well as Socket.IO/WebSockets

I have a Backbone application, which has a collection called Links. Links maps to a REST API URI of /api/links.
The API will give the user the latest links. However, I have a system in place that will add a job to the message queue when the user hits this API, requesting that the links in the database are updated.
When this job is finished, I would to push the new links to the Backbone collection.
How should I do this? In my mind I have two options:
From the Backbone collection, long poll the API for new links
Setup WebSockets to send a "message" to the collection when the job is done, sending the new data with it
Scrap the REST API for my application and just use WebSockets for everything, as I am likely to have more realtime needs later down the line
WebSockets with the REST API
If I use WebSockets, I'm not sure of the best way to integrate this into my Backbone collection so that it works alongside the REST API.
At the moment my Backbone collection looks like this:
var Links = Backbone.Collection.extend({
url: '/api/links'
});
I'm not sure how to enable the Backbone collection to handle AJAX and WebSockets. Do I continue to use the default Backbone.sync for the CRUD Ajax operations, and then deal with the single WebSocket connection manually? In my mind:
var Links = Backbone.Collection.extend({
url: '/api/links',
initialize: function () {
var socket = io.connect('http://localhost');
socket.on('newLinks', addLinks)
},
addLinks: function (data) {
// Prepend `data` to the collection
};
})
Questions
How should I implement my realtime needs, from the options above or any other ideas you have? Please provide examples of code to give some context.
No worries! Backbone.WS got you covered.
You can init a WebSocket connection like:
var ws = new Bakcbone.WS('ws://exmaple.com/');
And bind a Model to it like:
var model = new Backbone.Model();
ws.bind(model);
Then this model will listen to messages events with the type ws:message and you can call model.send(data) to send data via that connection.
Of course the same goes for Collections.
Backbone.WS also gives some tools for mapping a custom REST-like API to your Models/Collections.
My company has a fully Socket.io based solution using backbone, primarily because we want our app to "update" the gui when changes are made on another users screen in real time.
In a nutshell, it's a can of worms. Socket.IO works well, but it also opens a lot of doors you may not be interested in seeing behind. Backbone events get quite out of whack because they are so tightly tied to the ajax transactions...you're effectively overriding that default behavior. One of our better hiccups has been deletes, because our socket response isn't the model that changed, but the entire collection, for example. Our solution does go a bit further than most, because transactions are via a DDL that is specifically setup to be universal across the many devices we need to be able to communicate with, now and in the future.
If you do go the ioBind path, beware that you'll be using different methods for change events compared to your non-socket traffic (if you mix and match) That's the big drawback of that method, standard things like "change" becomes "update" for example to avoid collisions. It can get really confusing in late-night debug or when you have a new developer join the team. For that reason, I prefer either going sockets, or not, not a combination. Sockets have been good so far, and scary fast.
We use a base function that does the heavy lifting, and have several others that extend this base to give us the transaction functionality we need.
This article gives a great starter for the method we used.