[{"data":1,"prerenderedAt":450},["ShallowReactive",2],{"docs-nav-pkg":3,"docs-page-pkg-\u002Fpkg\u002Fauth":133},[4,8,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57,60,63,66,69,72,75,78,81,84,87,90,93,96,99,102,105,108,111,114,117,121,124,127,130],{"path":5,"title":6,"section":7},"\u002Fpkg","Overview","Start",{"path":9,"title":10,"section":11},"\u002Fpkg\u002Faccordion","Accordion","Components",{"path":13,"title":14,"section":11},"\u002Fpkg\u002Falert-dialog","Alert Dialog",{"path":16,"title":17,"section":11},"\u002Fpkg\u002Fautocomplete","Autocomplete",{"path":19,"title":20,"section":11},"\u002Fpkg\u002Favatar","Avatar",{"path":22,"title":23,"section":11},"\u002Fpkg\u002Fbutton","Button",{"path":25,"title":26,"section":11},"\u002Fpkg\u002Fcheckbox","Checkbox",{"path":28,"title":29,"section":11},"\u002Fpkg\u002Fcheckbox-group","Checkbox Group",{"path":31,"title":32,"section":11},"\u002Fpkg\u002Fcollapsible","Collapsible",{"path":34,"title":35,"section":11},"\u002Fpkg\u002Fcombobox","Combobox",{"path":37,"title":38,"section":11},"\u002Fpkg\u002Fcontext-menu","Context Menu",{"path":40,"title":41,"section":11},"\u002Fpkg\u002Fdialog","Dialog",{"path":43,"title":44,"section":11},"\u002Fpkg\u002Fdrawer","Drawer",{"path":46,"title":47,"section":11},"\u002Fpkg\u002Ffield","Field",{"path":49,"title":50,"section":11},"\u002Fpkg\u002Ffieldset","Fieldset",{"path":52,"title":53,"section":11},"\u002Fpkg\u002Fform","Form",{"path":55,"title":56,"section":11},"\u002Fpkg\u002Ficon-picker","Icon picker",{"path":58,"title":59,"section":11},"\u002Fpkg\u002Finput","Input",{"path":61,"title":62,"section":11},"\u002Fpkg\u002Fmenu","Menu",{"path":64,"title":65,"section":11},"\u002Fpkg\u002Fmenubar","Menubar",{"path":67,"title":68,"section":11},"\u002Fpkg\u002Fmeter","Meter",{"path":70,"title":71,"section":11},"\u002Fpkg\u002Fnavigation-menu","Navigation Menu",{"path":73,"title":74,"section":11},"\u002Fpkg\u002Fnumber-field","Number Field",{"path":76,"title":77,"section":11},"\u002Fpkg\u002Fotp-field","OTP Field",{"path":79,"title":80,"section":11},"\u002Fpkg\u002Fplot","Plot",{"path":82,"title":83,"section":11},"\u002Fpkg\u002Fpopover","Popover",{"path":85,"title":86,"section":11},"\u002Fpkg\u002Fpreview-card","Preview Card",{"path":88,"title":89,"section":11},"\u002Fpkg\u002Fprogress","Progress",{"path":91,"title":92,"section":11},"\u002Fpkg\u002Fradio-group","Radio Group",{"path":94,"title":95,"section":11},"\u002Fpkg\u002Fscroll-area","Scroll Area",{"path":97,"title":98,"section":11},"\u002Fpkg\u002Fselect","Select",{"path":100,"title":101,"section":11},"\u002Fpkg\u002Fseparator","Separator",{"path":103,"title":104,"section":11},"\u002Fpkg\u002Fsidebar","Sidebar",{"path":106,"title":107,"section":11},"\u002Fpkg\u002Fslider","Slider",{"path":109,"title":110,"section":11},"\u002Fpkg\u002Fswitch","Switch",{"path":112,"title":113,"section":11},"\u002Fpkg\u002Ftabs","Tabs",{"path":115,"title":116,"section":11},"\u002Fpkg\u002Ftoast","Toast",{"path":118,"title":119,"section":120},"\u002Fpkg\u002Fapi","Api","Runtime",{"path":122,"title":123,"section":120},"\u002Fpkg\u002Fauth","Auth",{"path":125,"title":126,"section":120},"\u002Fpkg\u002Fblob","Blob",{"path":128,"title":129,"section":120},"\u002Fpkg\u002Fchannels","Channels",{"path":131,"title":132,"section":120},"\u002Fpkg\u002Fdb","Db",{"id":134,"title":123,"body":135,"description":444,"extension":445,"meta":446,"navigation":333,"path":122,"section":120,"seo":447,"stem":448,"__hash__":449},"pkg\u002Fpkg\u002Fauth.md",{"type":136,"value":137,"toc":439},"minimark",[138,162,167,210,217,221,228,291,302,306,411,435],[139,140,141,145,146,149,150,153,154,157,158,161],"p",{},[142,143,144],"code",{},"lib\u002Fauth"," (Rust ",[142,147,148],{},"kalt-auth",") issues and verifies access JWTs. ",[142,151,152],{},"app\u002Fweb\u002Fapp\u002Flib\u002Fauth"," is the browser session. ",[142,155,156],{},"svc\u002Fauth"," is the HTTP service behind ",[142,159,160],{},"\u002Fapi\u002Fauth",". There is no Supabase Auth.",[163,164,166],"h2",{"id":165},"flow","Flow",[168,169,170,174,188,197,203],"ol",{},[171,172,173],"li",{},"Type a phone number and submit.",[171,175,176,179,180,183,184,187],{},[142,177,178],{},"POST \u002Fapi\u002Fauth\u002Finitiate"," returns ",[142,181,182],{},"okid_pending",". The app opens ",[142,185,186],{},"\u002Fid\u002Fpending\u002F{okid}",".",[171,189,190,193,194,187],{},[142,191,192],{},"svc\u002Fcommunication"," subscribes to that auth message and sends an SMS with ",[142,195,196],{},"{AUTH_ORIGIN}\u002Fid\u002F{okid_approval}",[171,198,199,200,187],{},"Opening that link loads ",[142,201,202],{},"\u002Fid\u002F{okid}",[171,204,205,206,209],{},"Approve mints access and refresh tokens for a one-shot ",[142,207,208],{},"POST \u002Fapi\u002Fauth\u002Fclaim",". Decline stores nothing.",[139,211,212,213,216],{},"The TypeScript lib persists the claimed tokens and attaches ",[142,214,215],{},"Authorization: Bearer"," on later API calls. Public challenge routes never send a bearer, so a leftover token cannot block sign-in through the gateway.",[163,218,220],{"id":219},"tokens","Tokens",[139,222,223,224,227],{},"Access JWT (HS256, ",[142,225,226],{},"AUTH_JWT_SECRET","), about 15 minutes:",[229,230,235],"pre",{"className":231,"code":232,"language":233,"meta":234,"style":234},"language-json shiki shiki-themes github-light github-dark","{ \"sub\": \"user-id\", \"role\": \"editor\", \"phone\": \"+47…\", \"exp\": 1710000900 }\n","json","",[142,236,237],{"__ignoreMap":234},[238,239,242,246,250,253,257,260,263,265,268,270,273,275,278,280,283,285,288],"span",{"class":240,"line":241},"line",1,[238,243,245],{"class":244},"sVt8B","{ ",[238,247,249],{"class":248},"sj4cs","\"sub\"",[238,251,252],{"class":244},": ",[238,254,256],{"class":255},"sZZnC","\"user-id\"",[238,258,259],{"class":244},", ",[238,261,262],{"class":248},"\"role\"",[238,264,252],{"class":244},[238,266,267],{"class":255},"\"editor\"",[238,269,259],{"class":244},[238,271,272],{"class":248},"\"phone\"",[238,274,252],{"class":244},[238,276,277],{"class":255},"\"+47…\"",[238,279,259],{"class":244},[238,281,282],{"class":248},"\"exp\"",[238,284,252],{"class":244},[238,286,287],{"class":248},"1710000900",[238,289,290],{"class":244}," }\n",[139,292,293,294,297,298,301],{},"Refresh token is opaque, stored hashed in Postgres, rotated on ",[142,295,296],{},"POST \u002Fapi\u002Fauth\u002Frefresh",". ",[142,299,300],{},"signOut()"," revokes it.",[163,303,305],{"id":304},"frontend","Frontend",[229,307,311],{"className":308,"code":309,"language":310,"meta":234,"style":234},"language-ts shiki shiki-themes github-light github-dark","import { accessToken, claimAndInstall, signOut, withAuthHeaders } from '~\u002Flib\u002Fauth'\n\nconst user = useAuthUser()\nawait claimAndInstall(okid)\nconst token = await accessToken()\nawait withAuthHeaders('\u002Fapi\u002Fpublications')\nawait signOut()\n","ts",[142,312,313,328,335,354,366,384,401],{"__ignoreMap":234},[238,314,315,319,322,325],{"class":240,"line":241},[238,316,318],{"class":317},"szBVR","import",[238,320,321],{"class":244}," { accessToken, claimAndInstall, signOut, withAuthHeaders } ",[238,323,324],{"class":317},"from",[238,326,327],{"class":255}," '~\u002Flib\u002Fauth'\n",[238,329,331],{"class":240,"line":330},2,[238,332,334],{"emptyLinePlaceholder":333},true,"\n",[238,336,338,341,344,347,351],{"class":240,"line":337},3,[238,339,340],{"class":317},"const",[238,342,343],{"class":248}," user",[238,345,346],{"class":317}," =",[238,348,350],{"class":349},"sScJk"," useAuthUser",[238,352,353],{"class":244},"()\n",[238,355,357,360,363],{"class":240,"line":356},4,[238,358,359],{"class":317},"await",[238,361,362],{"class":349}," claimAndInstall",[238,364,365],{"class":244},"(okid)\n",[238,367,369,371,374,376,379,382],{"class":240,"line":368},5,[238,370,340],{"class":317},[238,372,373],{"class":248}," token",[238,375,346],{"class":317},[238,377,378],{"class":317}," await",[238,380,381],{"class":349}," accessToken",[238,383,353],{"class":244},[238,385,387,389,392,395,398],{"class":240,"line":386},6,[238,388,359],{"class":317},[238,390,391],{"class":349}," withAuthHeaders",[238,393,394],{"class":244},"(",[238,396,397],{"class":255},"'\u002Fapi\u002Fpublications'",[238,399,400],{"class":244},")\n",[238,402,404,406,409],{"class":240,"line":403},7,[238,405,359],{"class":317},[238,407,408],{"class":349}," signOut",[238,410,353],{"class":244},[139,412,413,416,417,420,421,424,425,428,429,416,431,434],{},[142,414,415],{},"useAuthUser()"," and ",[142,418,419],{},"useIsEditor()"," (",[142,422,423],{},"user.role === 'editor'",") read ",[142,426,427],{},"role"," from the access JWT. Public ",[142,430,160],{},[142,432,433],{},"\u002Fapi\u002Fgeo"," paths skip Bearer.",[436,437,438],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}",{"title":234,"searchDepth":330,"depth":330,"links":440},[441,442,443],{"id":165,"depth":330,"text":166},{"id":219,"depth":330,"text":220},{"id":304,"depth":330,"text":305},"First-party phone sign-in, JWT session, and token refresh","md",{},{"title":123,"description":444},"pkg\u002Fauth","SD8CecGJdEGNsrihguRrtgZjBGZrG50tYdHU2JWCnWE",1791043754622]