[{"data":1,"prerenderedAt":379},["ShallowReactive",2],{"docs-surround-\u002Fdocs\u002Fauthentication":3,"content-query-goxeKexzyJ":10},[4,7],{"_path":5,"title":6},"\u002Fdocs\u002Fgetting-started","Getting Started",{"_path":8,"title":9},"\u002Fdocs\u002Flog-ingestion","Log Ingestion",{"_path":11,"_dir":12,"_draft":13,"_partial":13,"_locale":14,"title":15,"description":16,"body":17,"_type":373,"_id":374,"_source":375,"_file":376,"_stem":377,"_extension":378},"\u002Fdocs\u002Fauthentication","docs",false,"","Authentication","How API keys and encryption keys work in Lumber, and how keys are shared with your team.",{"type":18,"children":19,"toc":355},"root",[20,28,34,41,54,61,75,84,89,95,141,155,161,166,197,210,216,221,227,239,245,263,268,274,279,284,290,314,320,333,339,344,350],{"type":21,"tag":22,"props":23,"children":25},"element","h1",{"id":24},"authentication",[26],{"type":27,"value":15},"text",{"type":21,"tag":29,"props":30,"children":31},"p",{},[32],{"type":27,"value":33},"Your server uses two separate credentials: an API key that authenticates log ingestion requests, and an encryption key that encrypts log content before it leaves your process. Both come from the Lumber mobile app. People signing in to the Lumber app use their own account, which is separate from both.",{"type":21,"tag":35,"props":36,"children":38},"h2",{"id":37},"api-keys",[39],{"type":27,"value":40},"API Keys",{"type":21,"tag":29,"props":42,"children":43},{},[44,46,52],{"type":27,"value":45},"API keys authenticate your server's log ingestion requests. Each key is scoped to a single ",{"type":21,"tag":47,"props":48,"children":49},"strong",{},[50],{"type":27,"value":51},"app",{"type":27,"value":53}," within your Lumber account. A key is a 32-character hexadecimal string.",{"type":21,"tag":55,"props":56,"children":58},"h3",{"id":57},"how-it-works",[59],{"type":27,"value":60},"How it works",{"type":21,"tag":29,"props":62,"children":63},{},[64,66,73],{"type":27,"value":65},"The SDK sends each log as a ",{"type":21,"tag":67,"props":68,"children":70},"code",{"className":69},[],[71],{"type":27,"value":72},"POST \u002Flogs",{"type":27,"value":74}," request to the Lumber API with:",{"type":21,"tag":76,"props":77,"children":79},"pre",{"code":78},"Authorization: Bearer your_api_key\n",[80],{"type":21,"tag":67,"props":81,"children":82},{"__ignoreMap":14},[83],{"type":27,"value":78},{"type":21,"tag":29,"props":85,"children":86},{},[87],{"type":27,"value":88},"The API hashes the key with SHA-256 and looks up the hash. Only the hash is stored - the plaintext key is shown once, when you create it.",{"type":21,"tag":55,"props":90,"children":92},{"id":91},"creating-a-key",[93],{"type":27,"value":94},"Creating a key",{"type":21,"tag":96,"props":97,"children":98},"ol",{},[99,110,126,136],{"type":21,"tag":100,"props":101,"children":102},"li",{},[103,105],{"type":27,"value":104},"In the Lumber app, open your app and tap ",{"type":21,"tag":47,"props":106,"children":107},{},[108],{"type":27,"value":109},"Secrets",{"type":21,"tag":100,"props":111,"children":112},{},[113,115,119,121],{"type":27,"value":114},"Under ",{"type":21,"tag":47,"props":116,"children":117},{},[118],{"type":27,"value":40},{"type":27,"value":120},", tap ",{"type":21,"tag":47,"props":122,"children":123},{},[124],{"type":27,"value":125},"Add Key",{"type":21,"tag":100,"props":127,"children":128},{},[129,131],{"type":27,"value":130},"Optionally give it a name, then tap ",{"type":21,"tag":47,"props":132,"children":133},{},[134],{"type":27,"value":135},"Create",{"type":21,"tag":100,"props":137,"children":138},{},[139],{"type":27,"value":140},"Copy the key immediately - it won't be shown again",{"type":21,"tag":29,"props":142,"children":143},{},[144,146,153],{"type":27,"value":145},"Each plan allows a set number of API keys per app (one on Hobby). See ",{"type":21,"tag":147,"props":148,"children":150},"a",{"href":149},"\u002F#pricing",[151],{"type":27,"value":152},"pricing",{"type":27,"value":154},".",{"type":21,"tag":55,"props":156,"children":158},{"id":157},"rotating-keys",[159],{"type":27,"value":160},"Rotating keys",{"type":21,"tag":29,"props":162,"children":163},{},[164],{"type":27,"value":165},"If your plan allows more than one key per app, create a new key before deleting the old one to avoid downtime:",{"type":21,"tag":96,"props":167,"children":168},{},[169,174,187,192],{"type":21,"tag":100,"props":170,"children":171},{},[172],{"type":27,"value":173},"Create a new API key in the app",{"type":21,"tag":100,"props":175,"children":176},{},[177,179,185],{"type":27,"value":178},"Update ",{"type":21,"tag":67,"props":180,"children":182},{"className":181},[],[183],{"type":27,"value":184},"LUMBER_API_KEY",{"type":27,"value":186}," in your environment",{"type":21,"tag":100,"props":188,"children":189},{},[190],{"type":27,"value":191},"Deploy your updated config",{"type":21,"tag":100,"props":193,"children":194},{},[195],{"type":27,"value":196},"Delete the old key in the app",{"type":21,"tag":29,"props":198,"children":199},{},[200,202,208],{"type":27,"value":201},"Deleting a key takes effect immediately: requests that still use it get a ",{"type":21,"tag":67,"props":203,"children":205},{"className":204},[],[206],{"type":27,"value":207},"401",{"type":27,"value":209}," response. On Hobby, which allows one key per app, delete the old key first and then create the new one.",{"type":21,"tag":55,"props":211,"children":213},{"id":212},"multiple-keys",[214],{"type":27,"value":215},"Multiple keys",{"type":21,"tag":29,"props":217,"children":218},{},[219],{"type":27,"value":220},"On plans with more than one key per app, you can use separate keys for each environment (staging vs. production) or revoke access for a specific deployment without affecting others.",{"type":21,"tag":35,"props":222,"children":224},{"id":223},"encryption-key",[225],{"type":27,"value":226},"Encryption Key",{"type":21,"tag":29,"props":228,"children":229},{},[230,232,237],{"type":27,"value":231},"The encryption key is a ",{"type":21,"tag":47,"props":233,"children":234},{},[235],{"type":27,"value":236},"32-byte symmetric key",{"type":27,"value":238},", base64-encoded, used for AES-256-GCM encryption. It is entirely separate from the API key, and the SDK never sends it to the Lumber API.",{"type":21,"tag":55,"props":240,"children":242},{"id":241},"where-it-comes-from",[243],{"type":27,"value":244},"Where it comes from",{"type":21,"tag":29,"props":246,"children":247},{},[248,250,255,257,261],{"type":27,"value":249},"When you create an app, the Lumber app generates its encryption key on your device and shows it once on the ",{"type":21,"tag":47,"props":251,"children":252},{},[253],{"type":27,"value":254},"Your Encryption Key",{"type":27,"value":256}," screen. To copy it again later, open the app's ",{"type":21,"tag":47,"props":258,"children":259},{},[260],{"type":27,"value":109},{"type":27,"value":262}," screen on any of your devices that holds the key.",{"type":21,"tag":29,"props":264,"children":265},{},[266],{"type":27,"value":267},"The Lumber app keeps the key in your device's secure storage. It only leaves the device wrapped (encrypted) to the account key of a user who has access to the app, using X25519 key agreement and AES-256-GCM. Lumber's servers store those wrapped copies but cannot decrypt them.",{"type":21,"tag":55,"props":269,"children":271},{"id":270},"sharing-with-your-team",[272],{"type":27,"value":273},"Sharing with your team",{"type":21,"tag":29,"props":275,"children":276},{},[277],{"type":27,"value":278},"Apps can be shared with the members of your team, or with guests you invite to a single app. Your plan's seat count limits how many members your team can have and how many guests each app can have.",{"type":21,"tag":29,"props":280,"children":281},{},[282],{"type":27,"value":283},"There's nothing to copy and paste. Whenever someone who already has an app's key opens Lumber, their device wraps the key to the account key of each person with access who doesn't have it yet. Those people's devices then unlock the app automatically the next time they open Lumber.",{"type":21,"tag":55,"props":285,"children":287},{"id":286},"pasting-a-key",[288],{"type":27,"value":289},"Pasting a key",{"type":21,"tag":29,"props":291,"children":292},{},[293,295,300,302,306,308,312],{"type":27,"value":294},"If a device doesn't have an app's key yet, the app shows a ",{"type":21,"tag":47,"props":296,"children":297},{},[298],{"type":27,"value":299},"Paste Key",{"type":27,"value":301}," option. Open the app's ",{"type":21,"tag":47,"props":303,"children":304},{},[305],{"type":27,"value":109},{"type":27,"value":307}," screen, tap ",{"type":21,"tag":47,"props":309,"children":310},{},[311],{"type":27,"value":299},{"type":27,"value":313},", and paste the key from your plugin config. Lumber checks the key against the app's existing logs before saving it, then uploads a copy wrapped to your account key so your other devices get it too.",{"type":21,"tag":55,"props":315,"children":317},{"id":316},"key-rotation",[318],{"type":27,"value":319},"Key rotation",{"type":21,"tag":29,"props":321,"children":322},{},[323,325,331],{"type":27,"value":324},"Each app has a single encryption key, and the SDK marks every log with ",{"type":21,"tag":67,"props":326,"children":328},{"className":327},[],[329],{"type":27,"value":330},"keyVersion: 1",{"type":27,"value":332},". Rotating an app's encryption key isn't supported yet: logs encrypted with one key can't be read with another.",{"type":21,"tag":55,"props":334,"children":336},{"id":335},"losing-the-key",[337],{"type":27,"value":338},"Losing the key",{"type":21,"tag":29,"props":340,"children":341},{},[342],{"type":27,"value":343},"If nobody with access to an app still has its key on a device, and it isn't in your plugin config, the app's logs can't be decrypted. Lumber can't recover the key for you.",{"type":21,"tag":35,"props":345,"children":347},{"id":346},"user-authentication",[348],{"type":27,"value":349},"User Authentication",{"type":21,"tag":29,"props":351,"children":352},{},[353],{"type":27,"value":354},"The Lumber mobile app authenticates users via JWT. This is handled entirely by the app and is not relevant to SDK integration. If you are building a custom integration using the REST API directly, contact support for user auth details.",{"title":14,"searchDepth":356,"depth":356,"links":357},2,[358,365,372],{"id":37,"depth":356,"text":40,"children":359},[360,362,363,364],{"id":57,"depth":361,"text":60},3,{"id":91,"depth":361,"text":94},{"id":157,"depth":361,"text":160},{"id":212,"depth":361,"text":215},{"id":223,"depth":356,"text":226,"children":366},[367,368,369,370,371],{"id":241,"depth":361,"text":244},{"id":270,"depth":361,"text":273},{"id":286,"depth":361,"text":289},{"id":316,"depth":361,"text":319},{"id":335,"depth":361,"text":338},{"id":346,"depth":356,"text":349},"markdown","content:docs:2.authentication.md","content","docs\u002F2.authentication.md","docs\u002F2.authentication","md",1792656860499]