Encrypt OAuth Tokens at Rest: AES-256-GCM for Fintech (Simply Explained)
A plain-language guide to encrypt oauth tokens at rest. No jargon, no tech speak, just what it means for your business.
By Mike Hodgen
What's Really Sitting in That Database
I built a finance app for small online stores. It connects to a company's accounting software, their shop, and their ad accounts so the owner can see profit, revenue, and ad spend in one place.
To do that, the app has to store a kind of digital key. These keys let the app log into the company's accounting platform and ad accounts on their behalf.
Here's the part that should make you nervous. These aren't simple login cookies. They're live keys to a company's books, their transaction history, and their ad budget.
Think of it like leaving a master key to someone's entire bank account taped under the welcome mat.
Nobody decides to do this on purpose
The software tool that creates these keys just hands you a string of text. The easiest thing to do is save it as-is, in plain readable form.
That's how most apps end up storing the keys to a customer's financial life in plain text. Nobody sits in a meeting and chooses it. It just happens because saving the plain version is the path of least resistance.
The problem? One leak and an attacker has everything. They can pull a company's profit and loss statement, scrape their entire transaction history, and burn through their ad budget before lunch.
The fix isn't "we'll secure it later." The fix is locking these keys in a safe from the very first time you save one.
Why This Is Different From Storing Passwords
Most people assume storing these keys works like storing passwords. It doesn't, and that difference is the whole point.
With a password, you never need to read it back. When someone logs in, you just check if what they typed matches. You can scramble the stored password permanently and never need the original again.
These keys are the opposite. You have to use the actual key, over and over, every time the app talks to the accounting platform. So you can't scramble it permanently. You need to lock it up in a way that lets you unlock it later, like a safe instead of a shredder.
The key that never expires on its own
There's a second key called a refresh key. Regular keys expire after about an hour. The refresh key is the dangerous one. It can keep making new keys indefinitely, until someone manually shuts it off.
If a thief steals a refresh key, they have a permanent back door. It doesn't expire. They can keep getting in for months.
So when I lock these up, the goal is simple. If someone steals a copy of the database, all they get is scrambled gibberish. To actually unlock anything, they'd also need a separate password that lives somewhere else entirely. Stealing the database alone isn't enough.
How I Actually Lock Them Up
I use a strong, well-tested method to scramble each key before it ever touches the database. The same approach I use to protect medical data for other clients. Only the type of information changes.
The flow is simple. When a key comes in, I scramble it before saving. When the app needs to use it, I unscramble it for a split second, make the call, and let it go. The database only ever holds the locked-up version.
Why the lock catches tampering
The method I use has a built-in tamper alarm. If someone messes with the scrambled data, unlocking it fails loudly and throws an error. Older methods would quietly hand back garbage and let the app run with it. That's the difference between a safe that screams when forced open and one that just pops.
Where the password to the safe lives
This is the part people skip, and it matters most. The password that unlocks everything never sits in the database next to the data it protects.
It lives in a completely separate, locked-down system. So if someone steals the whole database, they're holding a safe with no combination. They'd need to break into two different systems with two different sets of locks. That separation is the entire point.
The Part That Trips Everyone Up
Here's where real systems separate from demos. These keys change on their own.
Many providers swap out the refresh key every single time you use it. You hand over the old one, you get a brand new one back, and the old one is now dead.
The trap is obvious once you see it. If the app gets a new key but forgets to lock it back up properly, two bad things happen. Either you lose access entirely, or somebody "fixes" it by saving the new key in plain text and quietly undoes all your protection in one move.
I've seen both. The second is more common because it looks like a harmless bug fix.
So my system catches the new key, scrambles it immediately, and saves it before it ever hits the database. And it saves everything as one clean step. If it only half-finished, the customer's account would disconnect and they'd have to manually reconnect everything, which for a small store owner is confusing and frustrating.
Keeping a Record of Every Use
Locking the keys protects them. But I also keep a log of every time one gets unlocked. Which account, which provider, what time, and what triggered it.
What I never log is the key itself. That would recreate the exact problem I just solved.
This gives me two things. A clear trail if something goes wrong, so I can see exactly what got touched instead of guessing. And the ability to spot trouble early. If a key gets unlocked 400 times in an hour, that's not normal, and I catch it before a customer's ad budget vanishes.
I'll be honest about the limit. A log doesn't stop a break-in. It just shrinks the damage and cuts the time to spot a problem from "never" to "minutes."
What a Security Check Actually Asks
If your app holds the keys to someone else's financial accounts, a serious customer is going to ask, in writing, where those keys live and whether they're locked up.
This setup lets me answer cleanly. The keys are encrypted. The password to unlock them lives outside the database. Key changes are handled correctly. There's a record of every access. And any old plain-text keys have been quietly converted, so none are left exposed.
Five clean answers to five hard questions. A reviewer hears them and moves on.
This isn't a premium add-on you bolt on later. I build it in from the start, because trying to retrofit it onto a live system under deadline pressure is exactly how plain-text keys end up "temporarily" living in production.
If your app holds the keys to someone else's bank, books, or ad accounts, and you're not certain they're protected, that's the kind of gap I find and fix before a buyer's reviewer does.
Ready to bring AI leadership into your company?
I work with a small number of companies at a time. If you're serious about AI, apply to work together and I'll review your application personally.
Get AI insights for business leaders
Practical AI strategy from someone who built the systems — not just studied them. No spam, no fluff.
Ready to automate your growth?
Book a free 30-minute strategy call with Hodgen.AI.
Book a Strategy Call