Personal Finance App
A fully featured personal finance app with account summaries, custom categorization, authorization, and custom home screen widgets.
Overview
I’m a very organized person, so having a simple way to keep my finances in order is a must for me. Trying to find a product to fit this need was a bit of a challenge, even given the plethora of options out there. They all don’t work well, have cruddy UIs, or are more expensive than they should be. So naturally, I decided to build the ideal product I wish existed.
There are a lot of folks that advocate for this design strategy, including 37 Signals. They always build for themselves first, and that method for developing their products has lead to their software being used by millions of people. Brian Chesky, CEO of Airbnb, also emphasizes the importance of designing obsessively for one person in order to build a successful product. If that strategy is good enough for them, it’s good enough for me.
Tech Stack
Front and Back End
- React, React Native, Expo, Redux, Django
- Plaid, Stripe, Ory
- AWS, Elastic Beanstalk, Lambda, API Gateway, Route 53, S3
- I used a Github Actions setup, with seperate actions for all of the application’s components.
UI Feature Highlights
Accounts
Custom Home Board
Activity Feed
MFA
Ory was a great service for handling auth with my application, and I think I’ll continue to use it for my side projects in the future. I especially appreciate having complete control over the UI. Showing up to an auth page that looks like every other auth page on the internet because they use Auth0 or Firebase is boring, and I like to show that I put effort and care into every portion of what I build.
While Ory supports MFA through phone and auth apps, there’s no way to remember a device. Since Ory is pretty flexible, I was able to extend it to support remembering a device. This way, the frustration of having to dig out your phone is minimized, and security is not compromised.
Solution
The server has to accept both aal1 and aal2 levels, so the problem to solve is how to know when aal1 is ok to accept. That way, we don’t force the user to authenticate with multifactor every single time.
- When a user logs in on a new device, they will initially sign in to get aal1 (via password, oidc, etc.). After authenticating with Ory, the client will POST to /device. During the middleware, if the token is set in the cookies, it will be matched with the user’s device it belongs to (if there is any). Then the flow will be followed.
- Now when when requests come through, in ory.py the request will check to see if there is a valid token for the remembered device or that the session’s aal is aal2.
- This ensures against all scenarios: When the device is recognized, the user will only be forced to authenticate with aal1 since they will already have a token set. In the event a token isn’t set, aal2 will be required and upon authentication, the client will call a special endpoint requiring aal2, where a token will be set. If the client tries to access an api endpoint without a token, and they have mfa enabled, access will be denied and they’ll be redirected to the login page. The redirect is done in the react private route when /user/me is called.
- The downside is that devices will need to be stored in the database. When the user wants to forget (and also logout of) a device, the token related to the device just needs to be invalidated. This will be also be equivalent to a logout, because then the user will be redirected to the logout page the next time they try and go to the page on that device. All it entails is removing the device from the device table in the db.