<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shlok Madhekar</title>
    <description>The latest articles on DEV Community by Shlok Madhekar (@c9dn).</description>
    <link>https://dev.to/c9dn</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1219095%2Fb76fdc21-f96c-4c25-925f-ad0e268a78d9.png</url>
      <title>DEV Community: Shlok Madhekar</title>
      <link>https://dev.to/c9dn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/c9dn"/>
    <language>en</language>
    <item>
      <title>I'm 15 and I built "OAuth for AI subscriptions". Here's the full architecture</title>
      <dc:creator>Shlok Madhekar</dc:creator>
      <pubDate>Fri, 31 Jul 2026 02:56:34 +0000</pubDate>
      <link>https://dev.to/c9dn/im-15-and-i-built-oauth-for-ai-subscriptions-heres-the-full-architecture-2a5a</link>
      <guid>https://dev.to/c9dn/im-15-and-i-built-oauth-for-ai-subscriptions-heres-the-full-architecture-2a5a</guid>
      <description>&lt;p&gt;&lt;a href="https://monet.gg" rel="noopener noreferrer"&gt;Monet&lt;/a&gt; is a credential broker for AI. End users connect their existing ChatGPT Plus or Claude Pro account, or paste their own provider API key, and third-party apps route inference through their credential instead of paying for it themselves. The app never sees the credential. The user can revoke it anytime. I have been building it solo since June, it is live and free through the beta, and there is a demo app running the entire flow at &lt;a href="https://demo.monet.gg" rel="noopener noreferrer"&gt;demo.monet.gg&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This post is the architecture, plus the reasoning behind the three or four decisions that actually mattered.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with "paste your key here"
&lt;/h2&gt;

&lt;p&gt;BYOK (bring your own key) is usually implemented as a password input and a database column. That design has four separate problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Trust.&lt;/strong&gt; The user hands a live billing credential to an app they just met, with no visibility into how it is stored.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blast radius.&lt;/strong&gt; If the app's database leaks, every user's provider account leaks with it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Revocation.&lt;/strong&gt; The only undo is rotating the key at the provider, which breaks every other place the user pasted it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attribution.&lt;/strong&gt; The app cannot tell users what their usage cost, because it never sees provider-side accounting per user.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;OAuth solved this exact shape of problem for account access years ago: delegate capability, never share the credential, revoke centrally. Monet applies that shape to AI credentials.&lt;/p&gt;

&lt;h2&gt;
  
  
  The flow, end to end
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Consent.&lt;/strong&gt; The app redirects the user to a hosted consent page. The user connects a provider account or pastes an API key, and approves linking it to that specific app. The page says plainly: usage counts against your subscription. Allow or deny.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Vault write.&lt;/strong&gt; The credential is encrypted with AES-256-GCM into a vault row. The integrating app never receives it, at any point, in any form. The dashboard will show the user which apps hold connections, never the credential itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Token issue.&lt;/strong&gt; The app completes a standard OAuth authorization-code exchange and gets back an opaque bearer token. Monet stores only a SHA-256 hash of that token server-side.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Inference.&lt;/strong&gt; The app calls one OpenAI-compatible endpoint with that bearer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://monet.gg/api/v1/chat/completions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &amp;lt;monet_access_token&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"model": "gpt-4o-mini", "messages": [{"role": "user", "content": "hi"}]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Proxy.&lt;/strong&gt; Monet resolves the token hash to the right user's vaulted credential, decrypts it in-process solely to make the upstream call, streams the provider's response back, and writes a usage event with the token counts the provider itself reported.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Revocation.&lt;/strong&gt; The user flips a switch, the vault row is cleared, and the token stops resolving at the proxy. Nothing to rotate, nothing else breaks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision 1: opaque tokens, not JWTs
&lt;/h2&gt;

&lt;p&gt;The bearer tokens carry zero information. This was deliberate.&lt;/p&gt;

&lt;p&gt;A JWT is valid until it expires. If you need to kill one early, you build a denylist that every request checks, at which point you have rebuilt opaque tokens with extra steps and a bigger attack surface. Revocation is the single most important promise a credential broker makes, so the token had to be a pure database pointer: if the row is gone, the token is dead, mid-session, no grace period.&lt;/p&gt;

&lt;p&gt;Hashing the stored side means a full dump of Monet's own token table contains nothing spendable. The same logic providers use for API keys, applied one layer up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision 2: one OpenAI-compatible endpoint
&lt;/h2&gt;

&lt;p&gt;Monet's entire integration surface is &lt;code&gt;POST /api/v1/chat/completions&lt;/code&gt;. No SDK, no wrapper library.&lt;/p&gt;

&lt;p&gt;Every AI SDK in every language already supports overriding &lt;code&gt;base_url&lt;/code&gt;. That means adopting Monet is a two-line diff in most codebases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://monet.gg/api/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_connection_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I considered a nicer, Monet-specific API. Every hour spent on it would have been an hour spent making integration harder. The boring shape is the feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision 3: usage numbers come from upstream, never from an estimator
&lt;/h2&gt;

&lt;p&gt;Each proxied request writes a usage event with prompt and completion token counts as reported by the provider, per user, per app.&lt;/p&gt;

&lt;p&gt;The tempting shortcut is counting tokens client-side with a tokenizer. It drifts. Tokenizers version, providers bill for things client-side counting cannot see, and streaming makes people estimate. The moment a developer uses usage data for metering or cost passthrough, an estimate becomes a billing dispute. If the number is not the provider's number, it is wrong in a way that costs someone money, so Monet only records what upstream actually said.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision 4: the app is untrusted by design
&lt;/h2&gt;

&lt;p&gt;The security model assumes the integrating app will get breached eventually, because some of them will. So the design goal was: a fully compromised app leaks no credentials.&lt;/p&gt;

&lt;p&gt;The app's database holds an opaque token. Stolen, it can spend inference on connected users until they revoke, which is one click and immediate. It cannot read the key, exfiltrate the credential to use elsewhere, or survive revocation. Compare that to plaintext BYOK, where the same breach hands over every user's actual provider key.&lt;/p&gt;

&lt;p&gt;That is also why the consent page is hosted by Monet rather than embedded in the app: credentials are typed into exactly one origin, ever.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it stands
&lt;/h2&gt;

&lt;p&gt;Live, free through the beta, a few dozen developers on it. Chat completions with streaming works across connected GPT and Claude accounts and raw provider keys. The near-term list is more provider surface and framework presets, informed by whoever shows up with a real integration.&lt;/p&gt;

&lt;p&gt;I'm 15, this is my main project, and the fastest way to make it better is people poking holes in the design above. If you maintain something with a BYOK issue open in its tracker, I would genuinely like to read it.&lt;/p&gt;

&lt;p&gt;Dashboard: &lt;a href="https://monet.gg" rel="noopener noreferrer"&gt;monet.gg&lt;/a&gt; · Demo: &lt;a href="https://demo.monet.gg" rel="noopener noreferrer"&gt;demo.monet.gg&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Related: &lt;a href="https://dev.to/c9dn/how-to-let-users-bring-their-own-openai-or-anthropic-api-keys-without-storing-them-in-plaintext-12m"&gt;How to let users bring their own OpenAI or Anthropic API keys (without storing them in plaintext)&lt;/a&gt; covers the build-it-yourself checklist, and &lt;a href="https://dev.to/c9dn/stop-paying-for-your-users-ai-usage-5bl5"&gt;Stop paying for your users' AI usage&lt;/a&gt; covers why the economics force this design.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I'm Shlok. I read every reply: &lt;a href="mailto:shlokmadhekar88@gmail.com"&gt;shlokmadhekar88@gmail.com&lt;/a&gt;, &lt;a href="https://github.com/shlok-madhekar" rel="noopener noreferrer"&gt;github.com/shlok-madhekar&lt;/a&gt;, &lt;a href="https://x.com/shlokbuilds" rel="noopener noreferrer"&gt;@shlokbuilds&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>ai</category>
      <category>architecture</category>
      <category>security</category>
    </item>
    <item>
      <title>Stop paying for your users' AI usage</title>
      <dc:creator>Shlok Madhekar</dc:creator>
      <pubDate>Fri, 31 Jul 2026 02:55:52 +0000</pubDate>
      <link>https://dev.to/c9dn/stop-paying-for-your-users-ai-usage-5bl5</link>
      <guid>https://dev.to/c9dn/stop-paying-for-your-users-ai-usage-5bl5</guid>
      <description>&lt;p&gt;There is a specific moment every AI product hits. The feature works, people like it, and then you open the provider billing page and realize your most engaged users are your least profitable ones. Every other kind of software rewards engagement. Inference punishes it. Your costs scale with usage and your revenue scales with seats, and those two lines were never going to stay on the same side of each other.&lt;/p&gt;

&lt;p&gt;Teams standardly reach for one of three escapes, and all three have the same flaw.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Raise prices.&lt;/strong&gt; Now your median user, who runs a handful of prompts a week, is subsidizing your p95 user, who runs an agent loop all day. The median user eventually notices they are overpaying and churns, which makes the math worse, which suggests raising prices again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sell credits.&lt;/strong&gt; Metered billing is honest, but now you are a token reseller. Users can see the markup, compare you to the provider's list price, and ask why they are paying you 3x for the same tokens. You have also just signed up to build a billing engine, which is its own product.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rate limits.&lt;/strong&gt; The cheapest option and the most expensive one. The users who hit your limits are by definition your power users. Walls are how you convert them into someone else's power users.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fourth option
&lt;/h2&gt;

&lt;p&gt;The fourth option is to stop owning the bill.&lt;/p&gt;

&lt;p&gt;Your user very likely already pays for AI. They have a ChatGPT Plus or Claude Pro subscription, or an API key with credit sitting on it. Right now that spend and your infrastructure bill are two separate worlds, and you are financing the bridge between them out of your margin.&lt;/p&gt;

&lt;p&gt;BYOK (bring your own key) collapses the two. The user plugs their own account or key into your app. Their usage runs on their credential and counts against their subscription or their credit, not yours. Your inference cost for that user goes to approximately zero, and "unlimited" becomes a word you can safely put on a pricing page, because the marginal request is not yours to fund.&lt;/p&gt;

&lt;p&gt;This is not a fringe pattern. Developer tools normalized it years ago. Nobody expects their CI provider to pay for their AWS bill. AI is the one place where products still default to bundling the compute, mostly because the first wave of AI apps launched before anyone had a subscription worth bringing.&lt;/p&gt;

&lt;h2&gt;
  
  
  So why doesn't everyone do it
&lt;/h2&gt;

&lt;p&gt;Because the standard implementation is a &lt;code&gt;&amp;lt;input type="password"&amp;gt;&lt;/code&gt; that says "paste your OpenAI key," and that input is doing a lot of unexamined work.&lt;/p&gt;

&lt;p&gt;From the user's side: they are handing a live, spendable credential to a website they met twenty minutes ago, with no idea how it is stored, no scoping, and no revoke button other than rotating the key at the provider.&lt;/p&gt;

&lt;p&gt;From your side: you are now warehousing other people's billing credentials. Stored badly, that is a breach headline. Stored well, it is real engineering: encryption, key management, redaction, rotation, revocation, per-user usage attribution. And then again for the next provider, because their key format and auth quirks differ.&lt;/p&gt;

&lt;p&gt;None of that work is your product. It is load-bearing plumbing that every BYOK app rebuilds separately, usually to about 60 percent completeness. I have spent the last month reading GitHub issues where maintainers describe their own BYOK implementations as a liability, in those words.&lt;/p&gt;

&lt;h2&gt;
  
  
  What good BYOK looks like
&lt;/h2&gt;

&lt;p&gt;Users already know exactly one flow for delegating account access to a third party: OAuth. Connect button, consent screen that says what the app gets, revoke from one place, done. "Sign in with Google" and Stripe Connect trained everyone.&lt;/p&gt;

&lt;p&gt;BYOK should feel identical. Connect GPT. Connect Claude. A consent page that says "usage counts against your subscription," an Allow button, and a revoke switch that works instantly. No raw key ever visible to the app, so the app has nothing to leak.&lt;/p&gt;

&lt;p&gt;Being upfront about my stake: this is what I build. &lt;a href="https://monet.gg" rel="noopener noreferrer"&gt;Monet&lt;/a&gt; is that flow as a service. Hosted connect page where users link ChatGPT Plus, Claude Pro, or paste a provider key. Credentials are AES-256-GCM encrypted into a vault your app never touches. Your app holds an opaque token and calls one OpenAI-compatible endpoint, and Monet proxies to the provider, streams the response, and logs real token counts per user so you can meter or pass costs through. It is free through the beta, and there is a working demo at &lt;a href="https://demo.monet.gg" rel="noopener noreferrer"&gt;demo.monet.gg&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;BYOK fits best where your users are developers, AI power users, or teams that already hold provider accounts, which is exactly the audience that runs up the biggest inference bills. Dev tools, agent platforms, prosumer software: your heaviest users are the most likely to have a subscription to bring, which means the users who cost you the most today are the cheapest ones to convert.&lt;/p&gt;

&lt;p&gt;The margin problem is not that AI is expensive. It is that you volunteered to pay for something your users already own.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Related: &lt;a href="https://dev.to/c9dn/how-to-let-users-bring-their-own-openai-or-anthropic-api-keys-without-storing-them-in-plaintext-12m"&gt;How to let users bring their own OpenAI or Anthropic API keys (without storing them in plaintext)&lt;/a&gt;, the implementation half of this argument.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I'm Shlok, 15, building Monet solo. Replies and disagreement welcome: &lt;a href="mailto:shlokmadhekar88@gmail.com"&gt;shlokmadhekar88@gmail.com&lt;/a&gt;, &lt;a href="https://github.com/shlok-madhekar" rel="noopener noreferrer"&gt;github.com/shlok-madhekar&lt;/a&gt;, &lt;a href="https://x.com/shlokbuilds" rel="noopener noreferrer"&gt;@shlokbuilds&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>startup</category>
      <category>saas</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How to let users bring their own OpenAI or Anthropic API keys (without storing them in plaintext)</title>
      <dc:creator>Shlok Madhekar</dc:creator>
      <pubDate>Fri, 31 Jul 2026 02:55:06 +0000</pubDate>
      <link>https://dev.to/c9dn/how-to-let-users-bring-their-own-openai-or-anthropic-api-keys-without-storing-them-in-plaintext-12m</link>
      <guid>https://dev.to/c9dn/how-to-let-users-bring-their-own-openai-or-anthropic-api-keys-without-storing-them-in-plaintext-12m</guid>
      <description>&lt;p&gt;Search GitHub for &lt;code&gt;"API keys" plaintext is:issue&lt;/code&gt; sometime. You will find maintainers of real, deployed, multi-user apps writing sentences like "keys are currently stored in plaintext in the database, this is a liability for the platform." I have read dozens of these issues in the last month, because I have been emailing the people who write them.&lt;/p&gt;

&lt;p&gt;The demand side is easy to explain. Users ask for BYOK (bring your own key) because they already pay for AI somewhere else, because they want their prompts running on their own provider account, or because your free tier's rate limits annoy them. Developers want BYOK because inference costs scale with usage and revenue does not.&lt;/p&gt;

&lt;p&gt;So BYOK keeps getting requested, and it keeps getting implemented badly. Here are the four levels I keep seeing in the wild, ranked from worst to production-grade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 0: plaintext column in the database
&lt;/h2&gt;

&lt;p&gt;This is more common than anyone wants to admit. A &lt;code&gt;users.openai_api_key&lt;/code&gt; column, written on save, read on every request.&lt;/p&gt;

&lt;p&gt;It happens for an understandable reason: the feature works in an afternoon. But a provider key is not like a password hash. It is a live, spendable credential. If your database leaks through a backup, a misconfigured admin panel, or one injection bug, the attacker does not get hashes to crack. They get working keys with billing attached, for every user you have.&lt;/p&gt;

&lt;p&gt;If you are at level 0 today, the encrypted-column upgrade below is a day of work. Do it this week.&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 1: environment variables
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;OPENAI_API_KEY&lt;/code&gt; in the deployment environment. Perfectly fine, but it is a single-tenant answer. It works for self-hosters and internal tools where the operator owns the key. The moment you are hosted and multi-user, one env var means every user shares one account, one rate limit, and one bill. That is exactly the situation BYOK is supposed to fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 2: keys stay in the browser
&lt;/h2&gt;

&lt;p&gt;localStorage or IndexedDB, key attached client-side to each request, nothing stored on your server. Local-first tools do this and for them it is the right call. Your server can never leak what it never saw.&lt;/p&gt;

&lt;p&gt;The limits show up when your product grows server-side features. Background jobs, scheduled runs, webhooks, team workspaces, mobile clients. None of those can happen if the key only exists in one browser tab. Level 2 is a real answer for local tools and a dead end for hosted SaaS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 3: server-side encrypted vault
&lt;/h2&gt;

&lt;p&gt;This is the answer for hosted, multi-tenant products, and it is where most of the actual work lives. "Encrypt the key" sounds like one line of crypto. The crypto is genuinely about twenty lines. Everything around it is the product.&lt;/p&gt;

&lt;p&gt;Here is the minimum checklist I would hold a production BYOK implementation to:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Encryption&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AES-256-GCM, unique nonce per encryption, never reuse a nonce under the same key.&lt;/li&gt;
&lt;li&gt;The encryption key lives outside the database. KMS, secrets manager, or at minimum an env var on a different trust boundary than the data.&lt;/li&gt;
&lt;li&gt;Bind the ciphertext to its row (AAD with the user or connection ID) so an attacker with DB write access cannot swap ciphertexts between rows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;UX rules&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Write-only. After save, the client never gets the key back. Show &lt;code&gt;sk-...abc4&lt;/code&gt; and nothing more.&lt;/li&gt;
&lt;li&gt;Changing a key means re-entering it, not editing it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Operational hygiene&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decrypt in-process, at request time, only in the code path that calls the provider. The plaintext key should never touch a log line, an error report, or an analytics event. Upstream provider errors sometimes echo request headers, so redact those too.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Lifecycle (the part everyone underestimates)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Revocation must be immediate. When a user clicks disconnect, in-flight is the only traffic that survives.&lt;/li&gt;
&lt;li&gt;Usage attribution. When someone asks "which user burned $40 yesterday," you need an answer, which means logging token counts per request, per user.&lt;/li&gt;
&lt;li&gt;Rotation. Users rotate provider keys. Your product needs a path for that which does not involve support tickets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A quick self-test that catches most broken implementations: can your support staff see keys? Does the key appear anywhere in your logs? If your database leaks tonight, what exactly does the attacker hold? Can a user kill access in one click? Can you tell which user spent what? If any of those answers make you uncomfortable, you are not done.&lt;/p&gt;

&lt;h2&gt;
  
  
  The buy option
&lt;/h2&gt;

&lt;p&gt;Being upfront about my stake here: I built one of these, so the rest of this section is the pitch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://monet.gg" rel="noopener noreferrer"&gt;Monet&lt;/a&gt; is the level-3 vault as a hosted service, shaped like OAuth because that is the consent flow users already trust. Your user hits a hosted connect page, connects their ChatGPT Plus or Claude Pro account or pastes their own provider key. The credential is encrypted with AES-256-GCM into a vault your app never touches. Your app gets an opaque bearer token through a standard authorization-code exchange, and calls one OpenAI-compatible endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://monet.gg/api/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;monet_access_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# opaque token from the OAuth exchange, not a provider key
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4o-mini&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The proxy resolves the token to the right user's credential, streams the response back, and writes a usage event with the real token counts reported by the provider, so metering and cost passthrough come for free. Revoking a connection clears the vault row and the token stops resolving. Only a SHA-256 hash of the token is stored server-side, so even a full dump of Monet's own token table is not spendable.&lt;/p&gt;

&lt;p&gt;It is free through the beta. There is a live demo app running the whole flow at &lt;a href="https://demo.monet.gg" rel="noopener noreferrer"&gt;demo.monet.gg&lt;/a&gt; if you want to see it end to end, and the developer dashboard is at &lt;a href="https://monet.gg" rel="noopener noreferrer"&gt;monet.gg&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you would rather build it yourself, the checklist above is the honest minimum, and I am happy to compare notes either way. I have read enough plaintext-key issues this month to want fewer of them to exist.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Related: &lt;a href="https://dev.to/c9dn/im-15-and-i-built-oauth-for-ai-subscriptions-heres-the-full-architecture-2a5a"&gt;I'm 15 and I built "OAuth for AI subscriptions". Here's the full architecture&lt;/a&gt; is the full design of the hosted option, and &lt;a href="https://dev.to/c9dn/stop-paying-for-your-users-ai-usage-5bl5"&gt;Stop paying for your users' AI usage&lt;/a&gt; is the economic argument for BYOK.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I'm Shlok, 15, building Monet solo. I read every reply: &lt;a href="mailto:shlokmadhekar88@gmail.com"&gt;shlokmadhekar88@gmail.com&lt;/a&gt;, &lt;a href="https://github.com/shlok-madhekar" rel="noopener noreferrer"&gt;github.com/shlok-madhekar&lt;/a&gt;, &lt;a href="https://x.com/shlokbuilds" rel="noopener noreferrer"&gt;@shlokbuilds&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>saas</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Hello!</title>
      <dc:creator>Shlok Madhekar</dc:creator>
      <pubDate>Sun, 26 Nov 2023 10:33:43 +0000</pubDate>
      <link>https://dev.to/c9dn/hello-4lm6</link>
      <guid>https://dev.to/c9dn/hello-4lm6</guid>
      <description>&lt;h3&gt;
  
  
  Some info
&lt;/h3&gt;

&lt;p&gt;I'm Shlok(Known as C9DN online). I'm a programmer who's also going to be making a blog.&lt;/p&gt;

&lt;p&gt;I'm not the best with grammer rules. While I do try to check my work before publishing, I make mistakes. If you notice something, please comment letting me know, so I can fix this issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  This is a coding blog
&lt;/h3&gt;

&lt;p&gt;Dev.to is a coding website, and I'm a programmer. This blog will be focused on programming, and will generally avoid other stuff. &lt;/p&gt;

&lt;p&gt;This also means I'll be using programming notation like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;hello world&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Schedule
&lt;/h3&gt;

&lt;p&gt;I try to work on a schedule. I'll be posting every Sunday at 3:30PM.&lt;/p&gt;

&lt;h3&gt;
  
  
  A bit of a warning
&lt;/h3&gt;

&lt;p&gt;I tend to "yap" a lot. I'll attempt to keep things short and to the point in these blog posts, but I cannot guarantee that will happen.&lt;/p&gt;

&lt;p&gt;Also, this blog may go into some complicated topics. If you have any questions, let me know.&lt;/p&gt;

&lt;p&gt;Lastly, Be kind. These comments are a safe space to learn. Avoid disrespect.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Constructive Criticism is great, but criticise ideas, not people&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I guess that's all. I'll see you all next week. Till then, stay safe.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Make sure to follow me so you know right when I post&lt;/em&gt;&lt;/p&gt;

</description>
      <category>introduction</category>
      <category>c9dn</category>
    </item>
  </channel>
</rss>
