[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"tools-page-secret-key-generator":3},{"page":4,"related":273,"variants":292},{"path":5,"name":6,"title":7,"description":8,"checkedAt":9,"sources":10,"faq":32,"related":51,"nuxter":55,"body":58,"tool":271,"preset":272},"\u002Ftools\u002Fsecret-key-generator","Secret key generator","Secret Key Generator for .env, JWT and Webhooks","Generate random secret keys in your browser for NUXT_SESSION_PASSWORD, Better Auth, JWT and webhook signing, as hex, base64, base64url or letters and digits.","2026-10-06",[11,14,17,20,23,26,29],{"label":12,"url":13},"Nuxt docs, Sessions and authentication","https:\u002F\u002Fnuxt.com\u002Fdocs\u002F4.x\u002Fguide\u002Frecipes\u002Fsessions-and-authentication",{"label":15,"url":16},"Better Auth docs, Installation","https:\u002F\u002Fwww.better-auth.com\u002Fdocs\u002Finstallation",{"label":18,"url":19},"RFC 7518, section 3.2, HMAC with SHA-2 functions","https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc7518#section-3.2",{"label":21,"url":22},"Lemon Squeezy docs, Signing requests","https:\u002F\u002Fdocs.lemonsqueezy.com\u002Fhelp\u002Fwebhooks\u002Fsigning-requests",{"label":24,"url":25},"GitHub docs, Validating webhook deliveries","https:\u002F\u002Fdocs.github.com\u002Fen\u002Fwebhooks\u002Fusing-webhooks\u002Fvalidating-webhook-deliveries",{"label":27,"url":28},"Cloudflare Workers docs, Secrets","https:\u002F\u002Fdevelopers.cloudflare.com\u002Fworkers\u002Fconfiguration\u002Fsecrets\u002F",{"label":30,"url":31},"MDN, Crypto.getRandomValues()","https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FCrypto\u002FgetRandomValues",[33,36,39,42,45,48],{"question":34,"answer":35},"How long should a secret key be?","At least 32 random bytes for anything that signs sessions or tokens. That is 256 bits, the minimum RFC 7518 sets for an HS256 JWT key, and it clears the 32-character minimum that nuxt-auth-utils and Better Auth ask for in every encoding.",{"question":37,"answer":38},"What is the difference between 32 bytes and 32 characters?","Bytes measure randomness and characters measure the text. 32 random bytes are 64 characters in hex, 44 in base64 and 43 in base64url. 32 characters of hex hold only 16 bytes, so a library that counts characters can accept a secret with half the strength you meant.",{"question":40,"answer":41},"Is it safe to generate a secret key in the browser?","Yes, when the page uses the Web Crypto API. This one reads its bytes from crypto.getRandomValues, the browser's cryptographically secure generator, and sends nothing anywhere. The secrets live only in this tab and are gone when you leave the page.",{"question":43,"answer":44},"How do I store a secret on Cloudflare Workers?","Run npx wrangler secret put with the variable's name and paste the value when Wrangler asks for it. Wrangler encrypts it, and neither Wrangler nor the dashboard shows it again. For local development, put it in .dev.vars or .env, but not both.",{"question":46,"answer":47},"Can I use Math.random() to make a secret?","No. Math.random() is not a cryptographic generator, and its output can be predicted from earlier values. Use crypto.getRandomValues in a browser or a Worker, or crypto.randomBytes in Node.",{"question":49,"answer":50},"What happens when I change a session secret?","Every session signed with the old one stops working, so everyone is signed out. Change it when it may have leaked, and expect the sign-outs. Better Auth can roll over gradually with its BETTER_AUTH_SECRETS option.",[52,53,54],"nuxt-environment-variables","webhook-signature-verifier","auth-pricing-calculator",{"body":56,"to":57},"Nuxter signs sessions with nuxt-auth-utils, so NUXT_SESSION_PASSWORD is the one secret every deploy needs, and its analytics salt falls back to it. Its Lemon Squeezy adapter checks each webhook with a signing secret you choose, and this page writes that too.","\u002Ffeatures",{"type":59,"value":60,"toc":262},"minimark",[61,66,70,74,127,131,222,229,233,255,259],[62,63,65],"h2",{"id":64},"bytes-not-characters","Bytes, not characters",[67,68,69],"p",{},"A secret is only as strong as the randomness behind it. The generator draws bytes, then writes them as text. Hex spends two characters on each byte and base64 four on every three bytes, while each A-Za-z0-9 character carries about six bits. The readout above the secret shows characters, bits and bytes, so a 32-character limit and a 256-bit limit can both be checked at a glance.",[62,71,73],{"id":72},"pick-the-encoding-the-variable-expects","Pick the encoding the variable expects",[75,76,77,102,112,121],"ul",{},[78,79,80,84,85,89,90,93,94,97,98,101],"li",{},[81,82,83],"strong",{},"base64url"," has no ",[86,87,88],"code",{},"+",", ",[86,91,92],{},"\u002F"," or ",[86,95,96],{},"=",", so it survives URLs, cookies and shell quoting. It suits ",[86,99,100],{},"NUXT_SESSION_PASSWORD"," and JWT keys.",[78,103,104,107,108,111],{},[81,105,106],{},"base64"," matches ",[86,109,110],{},"openssl rand -base64 32",", the command Better Auth suggests.",[78,113,114,107,117,120],{},[81,115,116],{},"hex",[86,118,119],{},"openssl rand -hex 32"," and anything that reads a key as hex.",[78,122,123,126],{},[81,124,125],{},"A-Za-z0-9"," fits a field that rejects symbols, such as a webhook signing secret you paste into a dashboard. Each character is drawn without bias: bytes from 248 up are thrown away, so all 62 symbols are equally likely.",[62,128,130],{"id":129},"what-each-preset-asks-for","What each preset asks for",[132,133,134,150],"table",{},[135,136,137],"thead",{},[138,139,140,144,147],"tr",{},[141,142,143],"th",{},"Variable",[141,145,146],{},"Asks for",[141,148,149],{},"Who sets it",[151,152,153,166,179,190,200,211],"tbody",{},[138,154,155,160,163],{},[156,157,158],"td",{},[86,159,100],{},[156,161,162],{},"32 characters",[156,164,165],{},"nuxt-auth-utils",[138,167,168,173,176],{},[156,169,170],{},[86,171,172],{},"BETTER_AUTH_SECRET",[156,174,175],{},"32 characters, high entropy",[156,177,178],{},"Better Auth",[138,180,181,184,187],{},[156,182,183],{},"JWT key, HS256",[156,185,186],{},"256 bits",[156,188,189],{},"RFC 7518",[138,191,192,195,198],{},[156,193,194],{},"JWT key, HS512",[156,196,197],{},"512 bits",[156,199,189],{},[138,201,202,205,208],{},[156,203,204],{},"Lemon Squeezy signing secret",[156,206,207],{},"6 to 40 characters",[156,209,210],{},"Lemon Squeezy",[138,212,213,216,219],{},[156,214,215],{},"GitHub webhook secret",[156,217,218],{},"High entropy",[156,220,221],{},"GitHub",[67,223,224,225,228],{},"nuxt-auth-utils writes a session password into ",[86,226,227],{},".env"," on its own in development. Production is where you need to set one yourself.",[62,230,232],{"id":231},"put-it-on-cloudflare-workers","Put it on Cloudflare Workers",[67,234,235,236,238,239,93,241,244,245,247,248,250,251,254],{},"Locally, the ",[86,237,227],{}," line goes in ",[86,240,227],{},[86,242,243],{},".dev.vars",". Wrangler reads only one of them: once ",[86,246,243],{}," exists, values in ",[86,249,227],{}," stop reaching your Worker. A deployed Worker gets the value from ",[86,252,253],{},"wrangler secret put",", and after that neither Wrangler nor the dashboard shows it again, so keep a copy wherever your team keeps credentials.",[62,256,258],{"id":257},"rotate-without-surprises","Rotate without surprises",[67,260,261],{},"A session secret can't be swapped quietly, since every cookie sealed with the old one stops opening. Webhook secrets are easier: set the new one at the provider and in your Worker at the same time, and expect a few deliveries to fail in between.",{"title":263,"searchDepth":264,"depth":264,"links":265},"",2,[266,267,268,269,270],{"id":64,"depth":264,"text":65},{"id":72,"depth":264,"text":73},{"id":129,"depth":264,"text":130},{"id":231,"depth":264,"text":232},{"id":257,"depth":264,"text":258},"secret-key-generator",null,[274,280,286],{"path":275,"tool":52,"name":276,"title":277,"description":278,"summary":279,"checkedAt":9},"\u002Ftools\u002Fnuxt-environment-variables","Nuxt environment variables","Nuxt Environment Variables: runtimeConfig to NUXT_","Paste a nuxt.config to get the Nuxt environment variables that override each runtimeConfig key, the type each value arrives as and the names that collide.","Paste a nuxt.config and get the NUXT_ variable for every runtimeConfig key, the type it arrives as and the names that collide.",{"path":281,"tool":53,"name":282,"title":283,"description":284,"summary":285,"checkedAt":9},"\u002Ftools\u002Fwebhook-signature-verifier","Webhook signature verifier","Webhook Signature Verification for Stripe and Polar","Webhook signature verification in your browser for Stripe, Polar, Standard Webhooks, Lemon Squeezy, Creem, Paddle and GitHub, with the reason a check fails.","Check a Stripe, Polar, Lemon Squeezy, Creem, Paddle or GitHub signature in the browser, and see why it fails.",{"path":287,"tool":54,"name":288,"title":289,"description":290,"summary":291,"checkedAt":9},"\u002Ftools\u002Fauth-pricing-calculator","Auth pricing calculator","Auth0 Pricing Calculator: Compare Clerk and Firebase","An Auth0 pricing calculator that also prices Clerk, Firebase, Supabase, WorkOS, Cognito and Stytch at your monthly active users, with MFA and SSO.","What Auth0, Clerk, Firebase, Supabase, WorkOS, Cognito and Stytch charge at your monthly active users.",[293,294,296,299],{"path":5,"name":6},{"path":295,"name":172},"\u002Ftools\u002Fsecret-key-generator\u002Fbetter-auth-secret",{"path":297,"name":298},"\u002Ftools\u002Fsecret-key-generator\u002Fjwt-secret","JWT secret",{"path":300,"name":100},"\u002Ftools\u002Fsecret-key-generator\u002Fnuxt-session-password"]