From 5a326bee4d602e38e9105deb8f24df92918338c3 Mon Sep 17 00:00:00 2001 From: Giannis Katsanos Date: Thu, 5 Dec 2024 19:29:22 +0200 Subject: [PATCH 01/36] feat: Unauthorized sign-in (#1668) Co-authored-by: victoria Co-authored-by: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> --- .../account-portal/getting-started.mdx | 1 + .../customization/account-portal/overview.mdx | 8 ++++ docs/manifest.json | 4 ++ docs/security/unauthorized-sign-in.mdx | 41 ++++++++++++++++++ .../account-portal/unauthorized-sign-in.png | Bin 0 -> 99224 bytes 5 files changed, 54 insertions(+) create mode 100644 docs/security/unauthorized-sign-in.mdx create mode 100644 public/images/account-portal/unauthorized-sign-in.png diff --git a/docs/customization/account-portal/getting-started.mdx b/docs/customization/account-portal/getting-started.mdx index 7a657908ec..b695c7cb86 100644 --- a/docs/customization/account-portal/getting-started.mdx +++ b/docs/customization/account-portal/getting-started.mdx @@ -20,6 +20,7 @@ For development environments, Clerk will issue you a randomly generated domain o https://accounts..com/sign-in https://accounts..com/sign-up https://accounts..com/user +https://accounts..com/unauthorized-sign-in https://accounts..com/organization https://accounts..com/create-organization ``` diff --git a/docs/customization/account-portal/overview.mdx b/docs/customization/account-portal/overview.mdx index 79fee3b8d6..f5287b11f9 100644 --- a/docs/customization/account-portal/overview.mdx +++ b/docs/customization/account-portal/overview.mdx @@ -52,6 +52,14 @@ The user profile page hosts the prebuilt [``](/docs/components/us Redirect your authenticated users to their user profile page using the [``](/docs/components/control/redirect-to-userprofile) control component. +### Unauthorized sign-in + +The unauthorized sign-in page doesn't host any prebuilt Clerk component. It displays a UI confirming that a session from an unrecognized device was successfully revoked. For more information, see the [Unauthorized sign-in](/docs/security/unauthorized-sign-in) feature. + +The unauthorized sign-in page displays a UI confirming that a session from an unrecognized device was successfully revoked. For more information, refer to [the reference.](/docs/security/unauthorized-sign-in) + +![Clerk's Account Portal unauthorized sign-in page](/docs/images/account-portal/unauthorized-sign-in.png) + ### Create organization The create organization page hosts the prebuilt [``](/docs/components/organization/create-organization) component, which provides a streamlined interface for users to create new organizations within your application. diff --git a/docs/manifest.json b/docs/manifest.json index 2528ecbe33..59ae6a3087 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1616,6 +1616,10 @@ { "title": "Protect email link sign-ins and sign-ups", "href": "/docs/security/email-link-protection" + }, + { + "title": "Unauthorized sign-in", + "href": "/docs/security/unauthorized-sign-in" } ] ] diff --git a/docs/security/unauthorized-sign-in.mdx b/docs/security/unauthorized-sign-in.mdx new file mode 100644 index 0000000000..b24a90dc29 --- /dev/null +++ b/docs/security/unauthorized-sign-in.mdx @@ -0,0 +1,41 @@ +--- +title: Unauthorized sign-in +description: Notify users of unauthorized sign-ins to their accounts +--- + +Clerk detects sign-in attempts from unrecognized devices to protect users from unauthorized access to their accounts. This security feature helps identify potentially malicious sign-in activity. + +## Email notification for unauthorized access + +When a sign-in attempt is made from an unfamiliar device, Clerk notifies the account owner by email with details about the newly created session. The email notification varies depending on the instance's configuration and the application's billing plan. + +By default, the email includes information about the unauthorized sign-in attempt, such as device type, operating system, IP address, location, and the sign-in method used. If you've set a support email for your app, Clerk will add instructions for the user to contact the app administrator. + +For supported instances, the email might also include a button that allows users to sign out from the unrecognized device. Selecting this button immediately revokes the session. + +To customize the unauthorized sign-in email notification: + +1. In the Clerk Dashboard, navigate to the [**Emails**](https://dashboard.clerk.com/last-active?path=customization/email) page. +1. Select **Sign in from new device**. You'll be redirected to the template settings page. +1. Edit the email template. +1. Select **Apply changes**. + +## Revoke sessions for unauthorized sign-ins + +> [!WARNING] +> This feature isn't available in production for free plans but can be tested for free in development mode. For more information, see the [pricing](/pricing){{ target: '_blank' }} page. + +For apps that support this feature, users can immediately revoke unauthorized sign-ins directly from the email notification. With a single click, the suspicious session is revoked and the user is redirected to a confirmation page. + +The confirmation page depends on the instance configuration: + +- [Account Portal](/docs/customization/account-portal/overview) enabled: The user is redirected to the [unauthorized sign-in](/docs/customization/account-portal/overview#unauthorized-sign-in) page, where content can be customized based on the app's theme. +- Account Portal disabled: The user sees a plain text confirmation of the successful session revocation. + +In either case, after revoking the session, users must sign in again unless they have an active session on their device. + +To customize the URL path of the unauthorized sign-in page: + +1. In the Clerk Dashboard, navigate to the [**Paths**](https://dashboard.clerk.com/last-active?path=paths) page. +1. Under **Application paths**, enter the **Unauthorized sign in URL** path. +1. Select **Save**. diff --git a/public/images/account-portal/unauthorized-sign-in.png b/public/images/account-portal/unauthorized-sign-in.png new file mode 100644 index 0000000000000000000000000000000000000000..456dd2c0ae64a1a4b198189a7a33b77568f0cccc GIT binary patch literal 99224 zcmZ^L2RxR2-}fnnq)-_lN?TbadsIRLEh{r5BrAI>gsh|xA*m!;WzXzNLb5ky&+Pqv zkM8?^-sgIr_w~6xpDT5q$9Ww8@%w$(|Mb1AD7TfGg_=YnZ9RYP>{SwJ^E`>PNs)>I zf72iy{0;xxXm#ei5*2=&sc!n<_g&U9YS!1xZ&};v-ZdZ@nwgs#a9io$H83!|`%&@@)EhYW+`oUH>fw>_hm5hWLOmO+ zHGeQ(JbEoJ>$pa~&1`>Co9XIPhc+Yrwqs%Yzi`*dpSL_MqeOT4GTn8G@Mm2d&NVsy zCqB`9<0CJO4)Ugb_RQ+L^R52pCk($2*mQE7?|QLk_qm`mv8OJXn}5D}Ttmpq$7k@t z>pCNgg!eRCw{Fceqo)7I&z1O)wp_Bgvs_Ql{O+d^5)%6NTMmVM=^p9xNK{sS`|jO+ zmBb925TAekh;A))A?@G3SyM|Z_O6wO5?6+e6<+an*V9N=O)X7}*}cl$4ahqQakATAoQyZl|Yj;ZIParlqCL&dq(9naOB#`{d8tCp}#M z@!qpPO>LGfVwAYNsF=p>84ZGl=N0h-l+JU#uDFhiB>nz}mr?~00-5AS@mrgKA)GgvLrl=#%7yLYWU zcaSgtk2{bt&QKq;7Bv!J5fBi3`Q{CUjg1XSo@)O5>#J|u+q-*vHzX+Co~^(W{m-8c zDo^=n-1yZ5Prr{R($%@&B_?Xn&gbOho_T$h|EJtPKZyA4=jK;ekF>Y9`+F~AsPhZ* zyFcrW|8pMx{w5lAI{Ok&SZQ0;7HY2&#<9Je|LZ5WXUJJFIGN@VPr3;(2ARjvt5brM9-#eQC*2Kv1wXSLB~J{ZqzRfaUKh5MUNR7*-Xl#1(t_@Qcfb z@6?Je7vqW)*D|GEU)`LeY39**MdR1;XWtr4_i&2U;gY$zqCcCOq~q&b{?}EjPYMb? zJS~X*f%nSERk9u&ti;6*=q@KFB+zF`Vb`RpJzstFF`tuuv)C|h?(dfU@1tgRSu|?f z?F<(Dcj5JR9v+^-WSPX~OPA*QWn0&Bx91RhmDT67tN_c_+qZ9DR#mOE{OSAOFW~dp zjJUldl~Q7BeE;5Y@Fs?6m^#AT4OhES_{~;W?ReeRbBPTPDYua9Kb`vL$k@tp2KziM z^L(VEx^-7tOmuF1c10nI#p#|;)%)+^VqZ;nzl9C<_cI#Dmj_B?eX#PM^$+$ z?Ov-hKO1a*kEJB)KYu((aTR;{;X`V6zJI>$N?2U|(B&&v?)@E!@|&aa@#8O#nz?n5 zmAaf2^1(=J7C1IER`2=e;u(IFsG9Pyw5|2TT>Uk>pURm<+BAtBA? z#6Jea$LCmYYlcbfkhR6#yB}<>`RhqZ*ci?guG$>JW7$}Rir#p1ZvUgI-$WI;@VZwD ztBiz#Q+qq3x9GtG3M?SoFF#5!FWY^~y3PN2FV|9I(yWwJRk0q5TUuHg73!{OX$7>l zs%r>&e13-_5!-OPr?*#cSEnFG)%9R!KBf6??BhwTC(-WpU&enb1Fm{8^#{fAGk}zN&Z0$qzJnyssvt+gu|F z%+@#k{5d)OhV_hs!q%PCULAMbI_NQ)9ZzKAiW?GD+iX7V2|m|7I!c4}xox+_x&7Pu z+1@tXj#Wv#qM>1;x>rh@U-}w1!xN?OB#}%P{Y<$?MANxbT+_bQ>%W|AlHQc_UtZWc6U`AZcPPb|-B~L#)=xyYc#0DcHBR&&$ zuQOzJc6OhCM+sfc!ti-}%f(9?TK$je8O)uU^1~6e1RJess76Co)zFr>UOno--#LzJ z)5TR;>xQf`se&f#a&mHSmAE36>WFG;XXowVAssKyk>dW(qV5!1Kh*4Pys4p~Axc#I ztzx{if`UT41V^w0>O{|EKI7j9zk2POeq(WrhX*sTID1^5LX^EdVS zxi}EhH{6gYXclY?e1a9ZH{{Fv56)IgLrJ=ee||HI+}%&QG1{C)a{p*pQ&L^MH99)F z*SfDVNUp2UWvXj^t?A&{E7p*VEGd)o7cP{%y%I+v<=IWh-n#WBK%-38!8g|{B7!9( z-UfAMq{ke?j?duEl{Zn^u>T)rS$Cv^ZG23Im?uz`no5RdG!u4L{X0piYOlV_@ zjud}$lO{fL_P)z~Vi2Bw{cgk({5Emx^{9x5hrfQ^1V$>x?S1+3CHr@%#+{D$$;vtA zC7zp6#G2EMLy{u(!Z4pGJ(hE$*D>Tgo(~>y?%%)BWohPKSQwKM7X#_VyLZ$K3=E&E zs!HqPo0OC>Laz3Y2Yfk>T{^sJsUmQcdznzLo*P;Fz~*4HNI=P7HImNHUPYb%mIM6pXa?&0R%y1G0sw3Ll)gPWyi zVR`uE$V17oNU;{raJ-pT`AQ0=`h9Kq(%itz_N3J3x-ZWha`WQ?9;CFsenU59yjvn>5aV=&yezJ-&K>?aE5bK8S%JN+IWet7-kEi#hi+Je54 zib`wd>HjK;i~`OJ7TI}uepwwI9sKz7Xh&WX1}+MyNH#8Qq4q^UK!D&@Vd~Nc8$S8& zI5he7Xv!W@QI;!Lu3#3*i#;eUN1OTIYvnO++qRA5URHMY!SdT{0KEhVnjL&x-C{!a zj%R8-fL($mAt9mH)QT&p<8XvI)#}nLxjXCeZXx^08?WNy{d5%HP;J>#8gfa}ccN&W z-Dz$#O>g9V>CZj)vE@TTLeAH3V;5(}sGMZk$adlu4Y0`MR3%4bgQAs)h{*N#jxlFB z$w>0i;=A-K{EI`mHBud>`?v9iy-mD(_wE@zJQ{{sGf2T4kFZBwgg8-1#DsBvHo%NMe?bIv?7Bl#yqVzA3uIv=u_nhYdh9% z7%)F9ONW_mZdUu*(9rYs>CsFx#jx(dK_C1LDRsg3*u}>eUN2PXtZm@n;BcO<7814@ zev%aVlPgD)r!Ymwc}gZ;%I)mgjb=rwwx~DV(=}2PGXq(#UcK5sHLM$b^WVGoC2K%! zysC@-neZZJ^)GZ&GiQmr1#j>88=nAszs~GACi;6OhYg`HHC~|6|TwYt~3*zb0)ivJk zyRkBegR(Y#2c_9J_b#k`|MMXShdS)W+eO$UotYOG7qhL0wxd0D|NiaOS>Uvfhi4mB zzxQ8`Rr)jG8u5WYm*!4n^gg_rATZ>9nKQV%n37|shf9p}pUodWd>}?`aeAN>4g1KE zBcH#1y?tWiPkMath1WkgDP@3pu))Kn+$5h|H~{jSN{qdN){g7-Nm-o_bF2nl$_24g z1XV{0fzCd&U!85*nkj)f6rcP=o;~y?(x1n!GvA>(RhPUmNy8g#E-^jI=WWj9qy^~| zDoWU{wR`eA*x7luOXUp{71_?i>~A1sLe5YxKU49?@;ww8`d~)fE6LM%ww7 z<9nK%!*7z3v=8T*H1Y7a4|I3CH#avcZn?$v^uoEqRi{ z^z(^~2wl|vo}r=5q=nyMI%PNA6cx8gu1rcF)6Qom@!kAP$KM_n9IX4}11l@5CCW;K zKvM0ki=G6{L|eOX@nT*4C61kpjOxx(+js8t3=e14%(LApwZ8IECQLyn8hc_R1x4?- zXD5WM2OpJ(Muvy`9Ex$?eyW~9yl8cfl}D$L2HT_^`-J)UO)8={zrN}lrtNtCc}-gz zt9jw#K}}7~%i7w3&!4kBmvmuy`t<2weLQVN5C<(UFE7eR96;>)>VzA2#~lcY;$ zGY@($d-`dbSqBFPPfkxuV|N7Z7P~dlZ+-6kd0%09io}x4u@bK>s5#OYWghK(qmlk} z4gB%z*RQpCcIHo>JejnU`ZoaXuo&fTrW{lqYs)ZU!b1}uOd=ZLWT(?a%RA#+#zsc& zDv2jW?`k=P17&R8ym@nP*TDBElao6>U_}+^`pN~cG#K|3%CS3a%<8aZEnFH-=CBpx(mfe*m;33+P-(QhEROzv4Yj>8n-Y)A(dE&PHTL(5ww{se z4A_Y$nwC~qkFa0Hnpx=eTFmO&9Kh6!M*Y3(1nMz5;JrZG|cXCazX0WIV8RtpGe{>lcmCT<7}laKXrjYDi@~u zrb=n0)QDXxQ3T*b7vnPbth0|*$n31TI!k{|Oc1)^)ibXiY7d^oO|Z%;2~ zH(rLPGN#L|{`~pV7T$dKw{H)B3+E?q%QTg~awS-%RbjVbz^w1*M&Jkt1s(IO+~_-fxCA!UekB*eeq(?;ing# zOSx&ke`7p>>FMwpJ>G8TlFBP2#DoFaWyf<+)OM5^f(Z}+nf1E6&h6Xp!Y8?Tcmze7 z58)%ru-xxga=5h*@;#mV_A@o{Of27G_sdtW&aOBO*2XsHJAAay1HS0(!qV>TdSkmM zQo~G{>VWz?`9$?3Sw+P_nNXRZ4I3#bOB)&(SOO?Uno@*Bt5tPeywH?Oy1F>9QXNk> zd$T)Iu>@2MIs@pd6*!)hTpHX5Y45D8?D2NFvnmHx?30p`8uAw0bHR=un(?=vG6YK% zcKGuuDN>gnRf}fyKT=eSJK%>B*VE3T&!5kI{;d%F82fog7?0Kl6443(0D%3nCkmGd zY=-e2Uj10_zLq=8r7auaR6nhVDFtF4TvfC1|9z%s0`%Z_D&|-DC0>PDc(6*2Mv256+Plxx149 zE+1wA8_848C21G5MpO?AyfI@cIURNcrNsZwpSzZ9^9L@5?m2pN3+QdQu;okP4i2}K zy=$u_TX@4ejZR$0a9Hmf>BtjufAh%HWcdr){im)jonzJ9Mn{?t9X@j8w528g%E}5I z8(aGn#SZ$6Gud4Hyu3k0JN_@!mw)o;kvkbV#i`d<32Y2{Xkle#@=?kG3%$1s?aAli z!wt1c$8KSUDe8p;1z!RIV}2o$mVg*rt}IxF+&5~}`(pJalg;utKmV1Ly!?DN2L}h! z?;la{kEy4hJ4S^M`D78ZTg++hPS(*op9-G`rX^Z*%@!B#IHbte+@y$(iI!OY;(+`$d`te~MQHeoa|a7%`Xl$4avac~6T6JMsM@5HX~@$-{L zlSa2wd@g)%bo36|dwMnv`i4I+>Dt=b&k?%Nl8HQ}<7l4pJVrG0>%uV25W81wb_FT)g-#~v&#DVb@E*Ku8Z z-N7*BxyZJAH~o$s`ql+Xhj;ec$v8c*-uYnUWY$XVS5V zT$@B~nYvIKfMeVO{0evZgQewuOu=Dc-n+$Y2bEdI2E|XGKFus-#zru-%ZD#xz*bhA z!8*wyM#~O76EtOc{`@&0#&^c1p1p`V}Sug~-=;Pc#>)zCSCrDS3xUAo7{wi+55YUWyRmXVQZ&asNGbMZ?3zTs1U zb>!9uQj`(NZ`i=O-QVc*_XzU|2lgv19=uqXLWYd=~o8x2y&e+=v6F3S$0duX}l&oc{z5iEVpU0Ir z+1N`lk|2|Zxw*^J^ef8*HLhZJ(Xp};OAU<`dSl$nmm9DRg&k+!c8YT5r+~^Y%r@z0 zX!fH9^4)3Xn;CA{0@ny!qztw8-u?R<_8&Z0f{zBTZitjqn@iTpBQV@Oa!T~<4X&=P zV7$buG5p*rX+l^9*p1*xJMUUq&9YxqRFqX#X0V;;Bu2R1x?Z8zRz*eS0j@jRo>Tv; z>)d}xtk6rTwFPp}KKf-3dCRF@nF6a3x3$GXz@=EU^}XVEbJ!#tXXxa+)L!fER|s0 zPSr}&7T45V$}dVwqc2+dvjw#No4U4Kc-vg#U(_q%C{VbzWa4onWHLN2PmGw=iHVf? zh2}JUe$!Tg{6AlhHW#@S*}I|2@muxFPi5xi<#mpw6fS-3&Y{@G=2NsfW{yI}Fu@7{ zP4cO+glOO~7at#AiV46_hl@KLhaxx2e(C)AVywI=bl_cEb9vNKNucGjUG>m-od0|| zv@qeeZZg@-oz;Gy&?vygdR;6nEyGbG=D;ffI5NsFzepf}1tp57-hsGRUMSz3S(o*UCOTyXFVs<>8 zuFIwcx+(YGOkSRzJtQu!Ns~%akaBKqb8zkdwhQXZ-ebpTE`}Z}zII8%fX*=-ZxNS} zu$=5Z9ddtnH57wb^R7bD4HeQc2tR&|+-ESb0g_PP0&PYbdlFL$kN*{P*qtX&%SQ-& z=}yD=to-J6JMHM`=sgg8;q|#omnsY9JGXe9+1ts1eL~8{0Hob+;3|mq-&Frb!2>eP z_ZX?J+u1eM)zyQB?VYAw?X$)!3sd$pb#guEL$!q<`(>4t`cu8-vTa@3z(;DCcb?VN zxV5Gm6U;WvvQIXW2b8*dZF!<{w_SUz-8vLNiyDdf8vwQo-5#_wXHNHzpYR8+Rr_$0 zpd~?mOuW6mhobp%I!;}qGj91{z$|W`TC9&r2G=fuP%%4BOHEz!!Juk}YajWiY|FkE z^+RP%CdYP$gY06bVcFmK^Xm)6$d7P-{YOAJPmikV{rViNmU@E>aByMa(Ozjj%igo? zuFGR;h0YFsWUykn*vVP8%y&4BBoS>73nsBg5=a28cF;u#^+W#I@l9S{UPS%I6U-E9 zP;6!K+`Qvp_osX0_5)FNG?McW8gzThd>y-B#J6Jv}`>lg48OHRhk( z$w(2IAN~Dlrj|eEfS?n10;vkv6%TZ;Q*x}g+)wW^&w&G*Q2$YDpKE8QESi`qC@ViL zmdw&Aa>UkN@V ziXH&v&aRq~0|yT1HoQ}I-0R%qBH=XmzRn^B4QFPko_Kk|vOaDUV@dSl&6~3x=;{3@ z3$QucarPZ-TD43%i-JNe=?65Y(YXp&=QLKZ6UJOxUiOrF>qF;g{$Su&Z2S1};|*{E zh!PC&B-C6;TufAxa0w?tu&#u8wd>b+{h6MIckz0DVr6lf zqRL?`qp22r9+L0S>Xyx$>%`V62+_GB*JebXwcJsZS4Q;vlTHp}mY7(=2g5CHfs{jF0>~r97@SR;Hhuo~?aoK8*q9g&S%2nx zYpctpm6enR1_t0F`ymtgNAIJdp(*pB-v_~nF#4a1SWz5Oe0~ZoATcK4EN3x+OD(!j zd3t)j`0!zS{H2%*UUmcw|H_OX+ii)`(2Z5BmS@ZT{kez-W_V_zivw^I z9usA>bsTaNQ|xtBD6XUEA+gaf7EW0DhIC4#IVx#6a2SDd7Pz=$62^dPi zO&~3(K&7wFhk&B`L+kFrYKDrG+L?bfVW&ys`_m9KVUIrC$|~56dV_U#1{MM#=6Sfw zJN1*fzrGm836%sFA`~PGT-PW=9fjfs<_$haWyDF7NsMndRNY%eZl=aHndaY@1dM9; z5DyJV1v%gZBq{=M35$pngARI7Y`x7t`9mAK&VH`NaPQL#gpwX5X7@5Rl@5@9uq}%h zfXcwuqKlfOkdD#N?fxE+8K%xK%Yp+mwI7?5kwl0W|0m zJl+*7O5Am(noBjaj*d<~7#c=J=JaVYLir{t1fhdE&C9~#!DP(#Z$_tsKD8NYB1nL4 zRVcTx(;T5S@H@^Jl~q*qeixhY3<{!+c3X3Zt4X|km`}fghEO-qa4K6q8lp}6FD%$Y zmA`>fv@lbD30#iwW1R7LXlCA;Je7dm{03ildU|>3*1eQLN6e`kprWDijEmcM+r%Wv zR-BcNjzlQPZCSK(fo!MGpWiGlE>3XN>}+A&gWiu<=N*?VUJPZwhKvlgqy+Lfo^%^- zTGD0dMtim;dg`Zqhv~_0Cu-D2y{#b5aveR&k8%o@(2Mfs*rmf=AP4$~)*$sLB*X*u z|I`NWMs1GToi8wrjP7sVxqENheFp3sh1ddiL@DSEAniTa#ePo@dc*rfH+}(hN)OoT#n6d`u&g28*C*ZRsfCDu5QwjCZgC z)15{9jFDU2lR%`%M$|>x;Q_O!zl)KPmggrbW2L<>1I44Zl$DncZHgBgj`e0Q0fiv` zRv}VwFZd#8DPd(76-h14PniGUW3A@a%%;QYI-{?@5A^y$e!e&&C;K2DfYy`%r?hIy zf*nJPhKO(<`;8!rlT%a0glRyOF)Sx|7h~^MOrYoAYcns}4P?IkC%l zT29>}T&=Vl#Tz{Q#wuZ2^6OXJD89d`*9B|XuHBLnHxp+^W{1k^{^mXv1U5m(y>>zD z5~ zrX5463)Go#Ntawf*L4lZQkt^9?!n21QK)l8ogrRp85Tf~`A+5ICstvLAFk1E_Nm>3p`eUsb6nh_| zY3<|XrG-Ev@bcwLx?Q^xnojd5-F8?W%i8+x9hGkEh=Ze}9^M5-hd|xhG9R$0ZW>PQqpXK2OkX55DxlR^0#>WEF#~*Hv1~Ihm<_GtAcHUpGQNqlG9a~H zmnaa9-3#_iPiUe>#GUE?IW1z>Q+NGk-Ho1IvwKc23BC7rroM$ zAxb_N2Srce&!0*d%ht37=(_>?(mCVe6CslV3Dg;c-~m#N6CO)Cn$&t0lJH(XE3>7UbK3vuBjIu7$H-m zOK~_)-Ycg4h`G`So)pyS2i)V+E2AQ`EtrNsx9IOiEk1N9y3DFZ!rN&)hf*W+4u9@= zRz{7{7in4vPjJYW0DqSxW}mbui^0&P1)WDfXFaN#{IjiM+ip=$l$2fHrXeCfER{z8 zQ_p|+2Xt~_C_aW@2w=ey=gyrwb?43hS)QYhRb|+s1%6)fn_GRptt~xNlIfkoA(nfnsW3RgXQEarSk0L|wb~qAl9Q7O;!Wy? zD_)nUK1SfxLKiW{V`}aIar(nQ6Fz_cF6ih#J~kGB)tf(6!FtP!ZDe>@-Psfy8rsz< z6wFSSc`fKSBNCEmZl8bOb)IcdC7!=*+3(>)3ov5w>2D{f&?!N+W*$&ZO-|AsEpSDH zbKE;b?1@{qdWkp<5++|#;tt@Rm<5dJNZk#pIt^kX>JXDq^qD1YnN$-64)6e#S$}r8 z!Ljl*dI?~D*}fogP8Gg8=V7jEI}RNv2)PEdE^BKmr~;7yAPRt~Zn#I1v;c#1E6)sJ zg<++aS=_u>>HHt!G9%UHy39?;a9GmPJYmuaN_wc4YDKOEogxC)_8&Ubhnw8KB?}<3 z7c(K0P1O{dtNy!?6)lb&ChDW$;Jw=4+CCayB5EdbECd6>0=aovZU4!W48VJ5kzea{ z9N}gYx2FRUA=F%J>-6GH?dT_!02j!jc@gLl;sMfoK7oN1=*fI|;QW~%7vWeJYI~iB zK+2@!OyASfLjVl|*J5x0BzJ?{ho3Z2iImo?EHCc?cd-Y|wS+q>ARusKvb&gYyfr~seReCvW%JEo%L?*adL`!J23rv)dIup%313j(q%O z5kL3Bp(NsM0T!VD1OE#bE|h(>1-2ejpHmR(@PuXlPF1+JhVc_gYwm>8?o zKqBXV`_oxilGIE0soyhmJa>c#2v8SYOxByFzfbYxKq=Vu( zh?E%6z2)Z?TFHe|ysw%b&wV35MPuTMftU6E#>2%`A~umv{$l7xOEcZu(AsFzE+t7x zNm8xxfhmB4huQ^>J#efYPa8UE^t;S=P`)@)cJr8fI*feCOR#LopykSj)ip|%hKpGB zcL$1%f66dv^4}KQ5sC^8?ek2MN*^K=0>)h&K(#PIe>OJuj%9TT=JKGhDAH636p4;H za%ao~qSBW-V^at^2A4oNF6ZdrcIl!ny&rMyK)Qr_E|o0vRjmZ2hi!o`GE4^nZF(7O zA(b-THdxNsS#o=97BVm43j*TER@Ejp+$Qok$i@P4GmF{2uNxpj8=!usX~SL+Ajb&d%O1 zmo7#PhKt&8k@lQ8QE$|o1m{%DcGSp91cGw?mbuNyIxQ4JMY2xKcw;cWi!@#^1XV-*W~*y zT33L35e=wKSQj-p*V#`L4??R$Q6#vHtE;58%d9eivacp69n;%K@TK?HKO#Ia*{mP* zH;jcA3Jsc2ke#sz90%?qW#pSTQOFA8ljx&@=AHh4&QNj4kiIB^_3aO8Pe|k0eSu;# z(IcT6X7nB|LE?X?=0;mQ;QYV}>BH<5zm)M)AB(4mpgs)Kj*3X=p^1F0stSJk6d=c* z?9?@jZ`IXF)$z!s`WaI=u!Ji!&C=HJ9Vt1Lj0<#`>Ofk}!B#p!_^=Mh~fnOh7r_{`XT=(RNvr$LIDR9Meo! zH;q^QWMyG-3LyUG@m&a6wHENS)hpAUk<&x>Y(41)R_XqR>j<|^Gj-`rij5mj@q|Sd za2(^}x}TMmb(%E@?g{)Fafp+M@s)j#5-a~+6H2w0S6^4`p2f*ev-dc?&eRQmXgiT_ zg&`uEB805S4qXj(b!rZd7!|2J6tj@fhQ{TCN>7e6lIW-?O;N4Kl54p_zNmL3pJWLr zp0ldr&gxF9WXD00a-by0@KUFeRP;eK2%Q`1A00AwyhSV9F?}bE*N+nk7QXrZNb{En z5o)ExA2`D|y;PG72^c9(XcUBTbH3_!jX2VwKy4)Tb@_QrFxCP=YT%wxC{rXQy+(yV zJgO2X<bPxIo3iF6rF-;)&BmPnRaBBxVAi_7So`D34ZavWx1!<0xoa z_V)Ja!W~{)n27vTw1g9ji)Qn|054N9Y3O%|$?pxTLVm~i2VK<$U5+DcMXhm-+A*mL z*y-`*i$}S*Qq8+0QIay5_1+_|-fS+BqZvq`Fq8-)lT-I1ijGbS?8L7!v_!H7Sn$lgE?4ektN0apgF+=JP zCF_}BSj@lVP{dhiWqF5r;V;X|QlPMU!`teu;w}2=#6wyDS-ygJHJ>@k0!T)8cXw^? zbe6U2JSvJ_MloTB11XvoGF~IhRRC1!)2Hv%6)FG%13*)n=TA{UrrHL?>8It>74iLh zVtNx$;?@nX=jfC&9kOYS-fctNx9oyERu!ZrLa)!2HT;w0g_5LHI} z&*yza2p4et0ful_M-x?4i?OjWf>Hdrns5L}3d&s(8qfySxNF0S_RPX^=e(}2E;N1c z$})5e7@265|B9P?oc_JnWV_@*<^|?06FGbZIqYsLmhEr?xFy%>FMheTJOT*Vk|OD7PhvGDM~qOlwql^f*c=GxyPQx+f8)BzJx|-N@0(p=Lb(QOMUMT zb>-X04rF}ow3(IY*?|yiNS}(f2~o^%JdZYa9MUi8>|Wz6ezWsr49-k}5^*c4UcI^jJ}@AwpM)J^FSlx< z0|=c7svMygV|?h@*#i;7)jBsAD0y?RyF&E<``OK17cXKUbb z{+$yr=PTKrg$@jb`XTeXR6*cD2*)I&yzK#(3la+2`au*lwq|PT z_+B0q?}AIFoqEXv@F^d;ABY_16cozgSNa983T3L*)k3XJ$^S!*<-4{reTjI@nB#5| zpYf0V-=Za0AxfO8ce(~e4!YjYpFcmfwYA+~kKGlE4q#NT22VcARDO-q z4h^@(5g{hR6NCc^po@*F3wBDNL?Zrk(xfq5z}iOR)zt*%?2MnT-&v}5o>3#=^y81- zAZyf9C~1Bh4be-8U7nqtP1t!v-Up|ds`($PJF#CyyAp9?Hnc=_BrTOZnz)v(JzAI+hmg+EUcadhKGE zZQ~pfw5C|beGpDIks5;C03!S^@0Bd{*mb=>$Mfnl-PTqd(C!IVyfC7(-a1sHgA;AA zY;WGY`3ZG}pPwHz=9pRT&_NLb2RwY@}my*LdwN&|T2F?P%d)GZaZkF~g zqEYSEbdBThuTRI4Um6Ay(l>#sAOX;0jlihe=C<6{^)0!#HQJ^iJ6ny$CR4WAPFY#` zx-+xcH7ey$g9{rqZ@Dh>jpvVEC{&{kX8XzNL}ke!P=*W+ZpiHJ_v8L zH#s!tnQEl*bdOjGwgPMfG7{mqCaHMiOp7drM=?gybVls;f&TpdP~u+>dQWXcaLZx$eyOV3A(u>?9U1S)OX{qc`|vCEMU+I@AQ6~g8qL#2PMHW1;k-CX zCMwO7&`{2kCmZ%OH?@<~io0V~>=hDfVyVug)}1+}JCl-0#bmX`%ice@>i45BH*t24 zZdnaPh=@s)NJQ~lCmo>j;!t-gAeEH}SNn;oT~pl^+N9m0oK4HeJ{c)ubr7N3I5UPn zX_-JA1sCKx_?syOl+Q0A{X);cu<3=dTCz}=bN#5I1$;m_6AJlJAtCy6d{&t^hPTzW z&y$lvd3DqyWt#t!1u*+z4U^7(@pl**345V;6}l-IJaUqN@}BEydYg#e0*?v1A>=51 zM*P^^1*#PSvR-)op|sS<7F%mmrg>K&f{gkISlExIRnjpqctPLrRpovz;lzkuijd?9 zv35i5GpCXq)NY{5!dvu!Zu8^y#WpR5+N(&i(86(}*)6KHqIg2qo;!+uBaTP*uDx^^ zYzxO8I+NINhU+OylI>tm53%ovcny*5Le50gnokVOg7k?9g*Q4Ld{55K&JJ^i-#EK$ z?%OpSOu(^QVNp>%#ALZ2ECcQV*pNQGfNbx4XJk)nG;zWPFb2U?5)ptPY(E0a0u)YR zOzrF!;rIfJG9{*7zyCVyI!wZM@3@d&K*BirT8RsZ&^QTR4GlvYb_x-*Cp3lk22>-+ z?Z4GtTxg_<9fG0?fR)bN%rK{w$+BHlIPGVv^39Soj|8bv?sBLrP|!&3h=0_)KiUyd z)P*1bw~7M9|6V<$6A>T#&~SX_jKNsugA?Yw1iRvJWd^(Y{N+nAn1@D`_FHx)M#jeB zB~zpheb1+~s6%lhvUuOV$$!If7NHL79fT-+HG2XI4{;n9zB+#5y_f$JIet4r|DB9{ zeapOvs3<2?vTqi|nGk}8VSUcXuB81EaWhFJmcK)ACaAHNUB`h=N!Jx&6pzhVY~sMR zdSr3PgiJU}HzP?gT+rV?EdjkzFZvhstHG;1g+%ZTA&suCu2(}fF;YR00cS>n$k1Vhc#Nc-ZBB_~hn=S0MFYIWrO%L6p?HvU?LP6+44 zF;j1FM~wX2bCD2^OkV`n?4>s@Z$v^uFWv?h{qf_+x25CCXmL0(#rZ%D=TcJ9G7{4p ze#mzm#BbkthC~4kLe^x?p7og)kW$Mo6jhsUE2#}P#ZjEGWQxWX&llR$x@;*~ZtJc9 zOP`?6foQlHo=j4Jnai|p#xA*in;E>IvZH42ldw8{0s>Ahslh2mjsORd6YaVWcnT5U zu|P9t(@!=BCPzjBc;jC4fkj>pCRo?p{C0kAi~RMNZ#b2|XDvGy9{y}*!$^5W#lz*$ z5!zo85(I)10& z5)vnSzV{(tW*q?o1`_GZ?Cj?5Zf)VijQ0nllHx|LfuJJTLH>#F#o+JX2Obow>)laP z+vm_fL4A3^g8=TLqn?croN{>J-|djgGwIsFfme*wDFR>W0)?lRby^(BlX> z@O+H}j>Y0jDP~4nuF-U8*I=l?JxDi#AI0Z5ySVg>j|WCXM5wskp+4Q&e<)T|dRli> zgL)t%{nAlhUZ$eb);6=A@GlXiYtSy3Npwt1hqPZi6~JaidDsb9)tqOSqTFiPq-D2P zSeO}dZ3Vh-SO1JREr%@p2psGp=G&1+H-;VWeZZK~v`boP#9A~hA~~U0`Cnm5lF?H1 zU7Q0IjpBaL{GT%(oXdT^y_|tm*Hl%#!JG9Fv?25>K18X~xY~)F4{I~u7!x3qm+@IE4 z5#3G-`)$MnkV8btY=)KM84C0|6ZJ>uI!-W7=E2HayqBem$Xjpt+^KomIWmQ(!V$DK zCxJV#F|Hk}Y-PbIsAI6YQIUIHx}2v2zUVS&oXFVsJz{T8e{6BTaw@jYTOqCKwl}V) z(+@o{I(lZZ9C!!C-nOp|3^ca*vVByZe57N@o+>MIBOgLFX)PKi$1W;}a{di4s2M|NJTE%=3}YzOAhJocMM8{0ZZO(+Ynaqw2|@Eow(U`xWUBEj}?Z z;EUj9&yP6t6Fd4ZRBKMRB@|Msn*@lni~1^Lppx z10kBtYsqS9oSn;^^NcPM5Pk#AT}CwM>8FNOi$uR8BD2@yLuhCyncZuDgBYJeYRw^Q zQBcF(>ob?u1%4^MK)AA^t#b}gA$x6U#CxUCWueD=-%H-f#fYZ-Tc51P#>S>P=L@sm z>prhr5s$L|aenGgSW&*w@B0=)Cx6Z_MvLmv3t^^X0CWoTvPB{L!b3%*+CTW&31^?;KE_ z(exe$6nE^o<$)IK_SvxNTvNj(x25_sR3ncs^7ulvbNDo2t! zBDHH$Q$s@|f3ez}o&T4(3Qk^oxp#K0RCm#ACXaC(PAGK^l@-4hKty2J{x}&SGHdx= zWWe8k&AGf{Kw`pyd?~YU2sJej2R~%Fo<2O9oUM1x$N~9ROW-Cs{0+>WkH@P1L|c?> zwrn+ympK^XTLT3o?j8H`uaHZOl9ZRk#?pmH-hX@;$N-0x@7Gk!%CAFdF3WR7LtC3K zl8Rnm8KAXy?J4n^Dx5Evpwq59fxfE;>@8E|24-%FMRoS<&M`5Xfyl0vTQ`qCgE4f= zd7+epeY+CQUia;o^*(}ci6U{uuREIo;X4mXb3DvKP)5d&GCec%??PCZ^p;|Sp{>+2 zv*YiruJ z7)Y+)i@2(_(E$_pM(bV+&l?%@`m>>KS5GyGN7CdNw{23oQ$_1octVUq3K=IzKsTLT9p zrR^)lI_Yty8P?-9VDA&bP2ZHB4BDAbZZBB$eG+MwYy4xQ>%kw^G;_aKM-8R?9z1xU zmUGwO?98S!l7E7O%3#%UKvhejbhZa6DG!!o-*qV3Uhg?(iCnU*5E&w-cV-F{i?0Rc zKHi+g(E(Wo`){mO`*qf9D;)-+n6RC4b941D&t6};xHU3&hPp_EJ9{NbKdt)xRXfKN ziBG~YuKaQ+hD}w|Qf8$=XI0r6L>S+HL5!Bym|5XsKO!>5&+mRcVhJ^?B2i~`n8;}N z;XVG1jg7=V9@EMdNXD7Xg_`x18cSmhl*{}PtqCC4T<8=!g!}<%IdBk0{Jub8&TX*# zeS8*5msUUCACx+q=%r}-=P9f?YkDUq-1St zTY-|W3kv~T=dyhe4qr2^PtvaQ-B>3I?io`=@qJN`49ccm{)EIFvu0bS^ivf1{bZp+ zsPM|d5{xxpCVWDgMNdg~&jVIH$isEO+{D{Za08erzE9+#a@kjDbZ!SFbR=9cxMR_< z?R43!zVT0?9G2&G&L&H@8p1y#?%uw}sdER;+um%q?+ZvXs0tm#@q9z6<(9g}M#h#q zg3uG*yi|TyxZE*Op|eu1Q+7peHv>3|!*e7}h}VaoFeJ|49R?`u1OMn_AFgJtuBmS^ zjM;ru<-L!!sFuAc;UF4Hj9j<;#$So=MSF<18lF-vfnQ#DdDAd7RR5)=C97{KYnblah?0vms+~b z52R}A+n*wxmF*cOs_%7*Bm+f<-)1Aq-PhyI5eOVJpJqGO>NB{-6N0p;x(gcsJBExqAc<3c-|h+K`H7AJ$@v`OVV|SDShg61l_LO5{dB)v zZt|aHS4@{b#M8=3$+;k#9@Sl6PWGaik1bUI~yDJ9K%=m!#z z4*A%(L5TeEx}xaInV6UyyZ&K6Gz&ef(KN@|;fFKjL14)~%ns)}eG1>*$LZL+c*(2D zoK)x~M&{;05VPgr3Fs#Ln0f+d3FO4533X!XK2!c41U+(_^BssUL8?UV8E3zB%l5P) zv#=9KR;<(0)61T!YVShq*B((IF`QB6fJ7lO7{G$vqmz%N9!NaTJLN=TmBGE@z=9DQ zoEU}2G#22toaN?sktb(AzC(k4!l`Rn58tmqoIa^U+Jm~G)NQd!C-8Pl^VJM|4!m8p zg{7B%JS?_t5LPR29!h6niMUy8*UHU@p3@KJhb`8) zX*cu2CE6;~P8X(m_dM|e1d6m5`kILbI^LdxuO#Ti8D8&|N?$CT^6Q3C42DrQD#WuP z`#~JHK6Y#s*&hGFp`jz~$BwfgymiyLkG0F^V~wO3660({Bh$y(YG`ltKx_8+jGbKh z8_r|FeHT$oL9+YPox%>LieLq;J8>t5!p z&b`PQ=l&CfKPZe^+lN4jKeqOMtat`w?}CsOFCz@Q+>vC~KSC=AeU&45!DjAQAK6PR z%sw35aUhJZ;Obj_C=~$!tcnXZ%LNlIyxO=8A~VzHvoFvG&s#=R;`P;{b=B~^#UEjX zJBbe{-6nQSa{5_K84f|{K}blmpXwDx4T^)*P&k*7!l2@MBnvD2Jj1wC`BCjF*)3~D z>&rz%DCwPr-*)zKzr*a4BUoQ3f-;{{V&Z}%9a|}u|DfSS6Lm?ba4G<9Bok3>4c+Dp zt@};DFO2J%fcK7`)y~-($%CQk0n4yN!53DA_!g1u#r{Z2rHj>V z02uiwqJcvBJzKpl9A6ci#+vk>aGlTVn`1X`&*p~?$~xgt`ZL{xYbsWIY!iu8RK zhnR)3L%lea?O(J~RpgH#O&OwAoMBbvZxkYXb=H3C;M6gfGK4SopO0kqEDfYr>0 zXm$iDCl*m0AX05?O_5F)nh+6jV>!+|RMhU202o;)45?(_(+h-UBG#Srf7tu;Xe`(F ze;mH6y?490ln7BOg^9zteOXg~;=XNr(H^UUvc z-gj4!DbdV5Or#fFU2j+f)8OG9|Lb z-DxZ+t(@6rZz?fSqc+mPke9Xja5(@fG)eOHe%wPlAUvG82~ZmY0|QczaeQSXY(CFF z*KPlF3R_QfD63N+uph)e|FF~1w$)mbh<4)16cYO!c_*`f54Rx>(kU-Jt3r~o14SfJ z)Cnis17-MyC-=YHmU^{}>)ssu?6qB4zdo$%d^zlBNVG^YboB~bR;1=Q2_wOR?rak& zyP7&O;_WO!DR67lFr#!r&oG4mFOAKo)=aferl&V z9eKwmCkqKnW+7U+UlcdwbnN7RRGy+mlcLRRBfSac3Q`D-uHT@S#{7 z29kYGM|YyP#ufHAXSw85izvL;jlC1ltvuIq1~WuQK5aFC20A`8Jzr+wBw$wC?mItS zB<)4~UZfA$9`3X`_dV4DX|E9?A;rbTI}+g6-kaY|2c_ZiUE^>AgUZ`JT`Z6d#J5Bq zO&-6yx-P+_@f0W*-E&%cVSM-Pml0=&xaDu(uPm?jChlnD_0%z9e1!cellZ3l`HFwu zp$6r^HCTLEC?l3{876*Hpq7pl3gG2YYc0n6=Eq~$-@PsxnZk(jeEVz2HFv55J_?N! zAOw2o&*~mQWRT$hj5Jm_*)-TSpxCJpRY4ul%kG5R;kJ*u{tRNv?r`Vsh>K6;+O{(A z@4V>(zK*RS(=yuE-~UOJk7##*fj-Ko`2lf2G_}llnTR%O%`Gcs845xcdqc=e#&PsS zv!Oi9op_HUa28CCH8HCM_a|xV&NbC<&n?#0Eh4$G!)%=m%4xg4Q}13?0R|*HTf!pbjaqNuXkRk&r)_g z?FXnsus>^U2Hch_=N}~IA#qF0;1|@%##LM$#Qzw%&*yllrg#ai;O>17isI;O-yoHH zBs(W((<~EeBWXq?LJ>sULEkgX*~ zA_*FI(p?qn^bnva>xusQq5=jzmMzr!QDVs;XP*qC60VQrPfLVqJBYCg2Lu+{*gfl* zO;=H-OUhAEV`WIHhV~6!KzbH&jmpMGu|#QRxP9bnbm(3qZUj7s(%IBZqslONK#U`{ z`NRrZoSzw~QByA1sw|;0Du(9a^V5O7KYudTs(KnUMn^?)AeTso$m0k+`KRMEM3Ks~ zSjvz+PdL(lLXxlhqO>x(70eKFE0kgu;(<}sZqU#V&=yJ5&@&R7^mP(??jwI4;g$Zy z_6k=Z*;u;e&XWJ#LRu z2wFU#RCh8ZY;J)FBRG!UrbqT`!PjPSn*L6<9pc(YeroGs6I_~uetH#grVWXIVpb3f zT^>Fa@d=Rl+k)$ri*|af;q&_1(!$bv)Be*~lxi$me*Yl`Hf#$n)%<@G63kmP)wrG! z6Z6!mQkNp}BS$*X2bp;0(X8V0>v}SJ?1$Oi&(`ejzyo?{^NJ*3qwch>QL+5tD_;oL zgH&7-ZxVhlQj9y5B}QZjhEnpi*6b9e&q@(^1zvr}_xmfzIylU^oId{sWG_P9A~RfX z49qLS7>oneTX5@#ND8oLuPb&iA`P!V}zj zGbN;*sxvC+THH-5ybwxMfn{0b4=i(*1-H;U>G;kx_J?NE3S9dcRJ0v$?rBEjk4IgANxhdOb&WOHkW* z6bX;5T@g>z1R_BUFej9>H(MP(53(X#F3bwmlalaNsL_9Hmir-*f0a#5;@^_@-kYP# zJ80p2jJl`!^`+yHK|Tjy*@xWh|LCn@Zax^pWd|GWXI~%FV?o}Bt5$FPghCw_bo^W| zp0lyGK5xTJIq;dU>-y_`cDJj@QXc7!hq+#-uE3)!8WKO09S#%;UZC&d!a#eTbIqI- z(FcfNikG9D{uV6qE%H09)x$neJ9UyRekB(f6nIv`wsz7Oy%C2P5={jm?od(_*W2$Q zP>zfnOvStpJSP)x=sI`(Lg`*1@uWB1!n>F|e_w0N1D5_OcT+Pn7VGFsP?Yc^LmKqL zdT(Y&ly?{b395FEa*=KhwjHDNOtCUYZAy~QHn_i!P-?jQRGWyP;HL|1qfd#i+rBuN ziI+4Vc8mvz6O>)-TvE^MYBe+q5JixRqE4ZQHM8Z$sTPOfcO#FVy}kV6f{hUpG$l3z zs@=VTFGyID7Fr-0A1Yp!_t_(atwfR5qZy$$QHNU(A4Ne#Ai2bD!T;kXr(bvBE4l$1 zLC78kCwfmk5x0o0Dx({^8w-dn4tN{#t(FKOc>v@=4t{vxg|p9Lg5r}`Hw7pz_jdHN z`MJ1izU`o=S*aNo?F2p3lf;qnKqLgFb>TudS|DNiU+BF`Tunt&e_r)bM3fw~y~capV9+(maI6B8!uXcWQHuXOUyUA335J?aK;(S_dA{J3!%366~5 z#T_9b6A~x=J_3ab5GrNIg?_!MB6%#&W$odI=cNGEa79|4b8K8u3N5s5?epCtmc$9V z^XEE%w{x)C|NM6v)+s|~yORTSrh2xUo6wf}_M5)qu)#~8MXcbcLFM5ot*Q)^IQVcS zrGX+T&cAvY_iJKTp_4*RILH(AHfOWNC=|7FBD@f5!!BWhXnTanCwoexS!B?kSkR%t zz>f!kM_;%m+(*>@KeYhs82rVRH>tJC=sH*5E}H+SapRS(SNIYZ$?!2Du}G2Tr6pN=U|J_K~7Z}?m@Y@+3HzWWlfFXzdc-6 zf?1=o-QF%n-HlTap)g8AK)@6@S0y!v@;O{iGr~k3tH*E3Mu8oU`J2cEK)BfG*jVFZ z$DbGkMn8;=OHNiXvU{;+>ixEA*bzcPk@Q_(E*~cH1Tl;&CK@AFQZOjC+LueLkY2t( zsOpV3FJ?*(qs=h(#Mf&F$HouUqUJ27N%OA{)I$X@LySyKAH~I0@eV^zqCwUjF?s*= zJ%OcN#D5`|cDFhA=lt^3TnMfr*9HH7u>7?2bd4YHcJ@n1D$@Jo!Nl`4F0L(Es$zKr z=Z)ASU@33YX`Y}mIpjRPH=O)-oKPM=0e{C$`0GV}w0?M4dD9b}$fUejMWr(VVX)1^ zpqZg3PHjx?ito3Edj;eYR4Ab4b1=Z`$?52Dxb5%{plqL}{eHsy%czc4@8eE|$tQ62 z%ZX1ZS+wh_JWkAuEjhAI?HrX#6%-MX2j+9YWCeT|=cPs9y*T69(L(D6Wl!|%e0*Xe zs#viPKVMC~?+mepZp?_cb9>w0lff1EVN6&Y^EgJ`8Vw&Gat6EO4#JPv9136DZO)vA z-gL`ejAH*T70>|zf(FY11Wh*fiq3F3LPfsNda5mssuS{aGw3!(|^AZId8ALWa`FZ#%A%Ulo{^OTw0sk^2 zAYg-Xw|W@=8&|b~!XXE$5rw4TU&^|CxJz*?v1^)}x9%J$6;Q5Ff0DQO#~g=OJL@4& zTzhWcy5-~YBm6d%!b;N2<_y0Y92~2ESl3zY_H{Nz0qA@Zw8I_-J_}bX%kuFQMwR7_ z0WJ#i8*7=dn}rp8ve79jv)E}t$wtWk8s*FmJPeZho3W}&wEg#X|2{W=GkN}o2GM=T zWD%Nykhcg9K54+E=Ol#mHt8usH)IdT8B)Iv}1 z9{tY})TKA}W8;2dOG5Qa;x`wRHh!Sy|I;ckB(e|M_gM2Q0Jy z{QRH)Lp>j5>8wN%RrcJQ`_H;47w=4LnxJ1d{a+-{|AT9LH}ibJe=T3p=lj#|JLg~g z_eUMa@!^?vH za|)6F&!yP^`FHleE1*#Rmj?e!10pc~|Cf9+;j@cO zTZdNRpK~7^iT`?c?&Ak1e5|+^E$|e|Uz>lfqPTR-PWk`2fIkn2&^~2976Wrz!FO1C z-3(Oe8D5mNQYh6Po1u|BLcY(|A9KdvEL`MZ7tW&>aq#0vKdEd~$5SW;G>xmMe+=gw znmOOWfMfJ&DuZM9zc?Yl{vI)&e=29;w2O3G`mlgl<r*y{Vahw() zPP=u9qAM;HaNwh-^u0ygor8^btHb2(l*b?Fa`D*{Z*tLm(XD;le8YT{{PA7)&axhJ zBHuh*{)SGXzY|ygcE&$dnX{p8YSA7iP#!DMp5%pM*U@HmCv(tNI&#t?+T`!k#A(^p zNLxVRd-b(>N|E)jo;v?M$7UCIuj3CwhR3JK$=^0BO&)5wY#~jdsDJq8G=6#G=QY!K zw7pMgH{Koa>U~ym(=|{bZjm}r%;>lE7a<8N?IHM|E3SBxoMwIa9S9U~Abd@}QeB+W zO0w``c0!Xwf1TWv+tvJR+-4;u|FYEqk@6pRtxj(Ix_k@TvmJGNye(jB2k2gGkhSPg zbNWWVfTSNcfr9i%pl; zj_rE~GASyr?vLi+$rrx0{!H=f_HSMH@I(RUXb0|zk-5mjd0Xm|B;rYTRp;LMuWiss z*-4|e|88>AU-JGNQz!J?;~)3nuLmMo?b>cWtv4k>qWqhC$PsYyH>PQ1E9gb);X_56 zg}It)ek0A;dJy!`P8t_ht41C-_g_EZZ!hKl#|p}c#|nRbma}S8_@i}}FYrQdmlZb^ zWO9j>BQGJqhHEENP|U^lnseRt5xXdqg|3ZnLd5F6HU8VS_ldN{n>!XT+pZ5RF6piD zmm=#>r>#_x+kgF}|DGBVJ1)xe26(*^9_e~wvrblGA8iZD+m{?4+7Cr&jL=@0s33X# z{4`&`wKfl{y!7Wzf9hviWZ~$??bpkpi%oaO>leGz^>4pDE;;;-%jw~bSI2h~0$(>G zY~*6Rd(HdY{=J=d_dP@HEj^V|&m=AWV#d`Axt-=$7MXKoD76fw({m?AtTHZY2%hVEk!rvfL z*LCYr=A~aU=iM&l@^cl9YwwHWTS@WJ-gEy$VG|oqWRcz1GcBQaJzGL{O67~R@NdkJ zu!w#CM&b8sXWU74>P3aX_3yEwi3xyxAc2KEAiQdXV1C@#m-cTvi&pG#{lBO4*7SpR zz8i&(o;4Y^&YzKMmQ;>p_jiX+?oM2Dc6$Y!jVVp=~lu6{lT5r+vq-6&6w{OzrLTmaYcFz1L<^9Tz-}qnb#JtN`F12>mwOL zH2I_6ht~|#!O&eh0r!ttNGM%JO>HNfI*tM&=}Wq9pdMn+lU`3nj-8T{y+3>Hx}$>O z`oV)F-Y^1xvflivpOb1VkLm6EhXia~RB4XIdV{cs!i{D&HO*e?2^Lv4(Qs!mWd`o- z7V4>+NJ7XSKW>1ih}XZkQU2ws>L*?cb2;Ha@i?>y2r5s&?Z==&n1hk!F|#Rs9ttP; z({2sWHdHL!Qwk;2)s3ajPb=BtAZf&<q?TW?ZA!)Y#Y!F)seJ?bx1cNf`rD{ygeq zBo1riaY%PXo?GI#WzyKt#G0()r`J~__F125HOw*~`5^SpBU+5U3RESb=F%(j4Hmd9 z4W(p&lTyayothf*72I@&R+}szz1S6bs#80-X%tSODeePdEgzrz#tnO>DJPphY|eux zPEshy0hpNf>!Wk=Y5Sj$k3V})7NH|)&&we+pugdt=zX`(BDvFq`e^k=mIKBIRZAERBMflP z8L4Fw`5kF^M%bVjNX&EWYy)_FW-Esk(D>0vJi z?{i&UsdL#V*pM|axOH$hc!_3F0L35m~CWk z?uj@a5`NB(g7j~+*RPq`!0?N?jL}HY8$>-MMdRX=#uEE|3Yi9&2QB9;nlS7JON%p& zL(NHg+5;@hBQzmF2p{Zud0HMFn%_s}10wt^6*()OIXEJ6a!7}^&HR1_er@~pM62Kq zbqiHvj-9@;sztj^4(C^^p0cu%;hNPL?iUdKCh~j)&qDFvN7E+a{;!%en`F+J3MrTu-}FHh?hK~^F#U3yQ` z^!_#ulgCD{N>6Rb+-4Cm8(ez%FyvG?+Qc9W70h|DDPmA>EsGZezCc`=+UZ~OEn#EA z9X(EixMlUMXh@j*XvaR|!_nt1q%;n&Em?g1ajq{=ff29@?CeN!><?-fef_D$O`AXW&eL3veV`@&Ko`83)cjSYiAa}#3 zZ!mt5m3kMfR(L>ql5EQq$AThWgZOWnC8DMhe-kUU8o@#e#YfaXn8Gx8xz49dbs?m* zi;YV?AIH<|oqJGMyy|_WT{rH#w7c+^hSumgc?dk+XJ2H{tiZYz5AH_eW0~0Ty=B*X z*jSpFuW`2hvuVSIxyT2voFU*24UHOjFB&}l&NaQE$?CIH!CvbD!nyv-Mo62{erjRL zHjBm5`IMZQ!CB3M&r4vx0HeD_dlxK@xlebV>)y2@&(}+`Nf-}&hQ>U*__@-xtBpR` z-n~n`pY&*32lLw&dQg;ZeADy>U#2W2&J}r;UO9z9{P1B8)zaw9@<~8r=E2zk=4nTn z@eA1{GFZIN-c^O1cjKpI*I#&Vkskm}>9U4qq3%7lFJ9E+T29CN+{L-=2~L$3%v<%r z1TrPw|2$wG8)y5tUhk!2mhWj_YLRh{YE~@RHK2qh@8rIUs0dy^%+2t|sbYdtoYTgq z24VE?T76-7MZp%EJ4IE^K^7qStMmfz(XaZ1!Q**G4*KIoVs|w= zB^!JS$-`Wnr#-n^`LxC$vtW=vQ?{~6{-l8^zRH(jG;Vp!H97rl^`;bwB-*y_q1hO*o}tW}0A~pwpryYZ9L^QLEQKdA6T-E!U9yMU8FA^#6R~a^1D!kM+m8 zr&bGHejIo?Mfn3&Pc!k0)zcm^ftXu2q{Q|=yZk&pV%@ZVW<1?5(@%DIffP;}rLNYq zJQ5d@7ARYL_IZ<;%|NOVxJxkFtouNq&9C^l+3jz{@<1h{K-$q~!!zWMUZMJ3i|o9W zr&R*jl=xan9#IfWDK=xwFR5G9-}YCj%~WnvIrWP#ZW2c`8q?Np$T^@src2-G^N%4d3Zt&CR2ncymyn|((tPUbo2u}60w@7BZBOlcgNX4J^rR?{Wg=6*zL?_zTz@1;C5 zbRtp&({7IWn)L`3Up~CALi6m|I-{bo=K}abohI}*Z?TqCjT=37UT1q5Z5h^9{<90m zR6p*lK;GmiEie#TV3MUX7boo{;#-w5^v41g5mj@>DnOCRh*0%ep04_j2p;*@NpXc!E( z87?A7@)~&@{9nc7v(DT=6)u&w*ZO631C5l%G*T)ha&C7pq1LEJ>desvHeDHMai?zW{(aUa~>$4xQI8Jv67uQ<1yjr!8`@u~ERa3Rcp5Nbx zcO*s?+8;Z_;Kg)9{)W{q5aj{Qi4=@&IsfBi#9Ol%&@3r_W-~YWN^ODvjc2NZ-nB0d zHw=eBu`{;Ite_TR5d7SvK37qG3|dk!-K=N7Qo4g4FH0-v|CNp=6qPt^w;LTE-s@{z zpWCDz?HuwZ*#X@2IyqLHA@52~QhTZs8N9j)1A`^G zH&~fno4EZUO8j}fHcSPh;^k{=72FS2OwOAfbts_~>(H11|ahAH8s zlp3e0Tt%y}q{R3-1?-c-1l*DM7SN!WAdSKEW2QV@7r{{tLC=( zuLJPVf)5|O$hjP6CCG;bchbbHu#`0n0otnAg+_;{jndE*E=@H1PwT$oy3>tM>#x4& z3UX*l2Q5F-r@xG^F?3RIf3pLNVy3-7u_S))9|^+(@foFWO+#eC5uu#^75}6(yh|Fg z3N;gb4yhK(yG+_s?ADhK1nrAz;@#UwyP(iSU^LM1I$F2_6~$>suAp7iGg0WzmN@D1 z5*l%@#Tr9)u{Ji-rAJNSm6&NSUrx8{e((dW>B1`Sa%@w|Ntu7tlU=~oKOPr8?+<`U zK@r?Y_&cZ3d_HCVy zSd<^@o_(>uz6e|0$BVqk-#pFo?L*AJ!Eb}S;)QX}}T;CSU*=IR&Z zPca$=d9X3Wxnz@ciQso!V=43IeU2Nd$fu#r&RsmR{6++mAbgo$oZo7 z#iJwiAuoF;>>G>z;5kcsAR8;6nm0<5R$);Fr@=xP6i3L~SL}<&IGSiOK;t(f3G%4< za`BwoUmtvo^WNmoWA&k3#?>w0P>PXJ?{+_~r~BB$Zaiw@J(ge*(%lfZ{=)eAA1gz} zf$VEZYWdLlkJ)c~f%5izRFWP2-lEwygG>P9;&Iji_Am-Wyii6WGIoTrOH)IH;Uvcs z-xKODKJBgYt94u|8RRa1^SJo(-l{JzO~$a9T|8-0+viCi+k;aPxn?eAIvECZKURfu z0LF9#)$H&|1&CvsjH*heIW!m_LbYQ+Mj{Z_ldDf3DZoSz{but_&$kk*Z74qHGrnj4 zweEZ5m*PH=f3~g%j|p=u%edNeyR+S=5_)%VPPmO*KYdA=E&;N9XL`NvBh(2MVwf-U zKrZHdp2QedF%IQm763Ew-}?2f;mR`|{bxEh#;*-2UvCg`OXm^)D<$fycEN1n+J-el zAY%k=AI3yJ_gY9$+DS>!1L`rs7AB)}3ed>Jv|vYStI(}1zuBu(rhztGrYgx?KgcdCdHwvsUItf}47|{_Fab1--otey|`&RVYo35t;qL%uY z0VZzKW@mV5gNx^h)?@Y)a}LK2ZN~fjPUEZu1*M$6T5C7X=8L*rHg2w)dsj6~zeVE% zt*H=IvJEZAQT9x#j8Xr{h)9Je&~6W7x=BsT@s*)&8o@!AnLosvo=fT&Bd_ekkPCPu zou;zWj=9x5^YlwRwPsYq-b-heB7BBpq> zQe23XxS}8O5xTpCr>;|szH3$SI`SC5!is3ymtOGZ*WviNHJewaUBd|FOXv)jLc7P= z9tSfNjbjL$%TK@n-NcL}RAkeU+D1}dDkF39ZJ1Kd`ED|!(MIVp_*7msl z7+MpiWdVZDE8J|BD(=nf((?51e&hTzK|U-*IG@^^a0u_sGc;Gt^ZBe{oSt5={U`N; z47a6>*mF;Zth+>vsl z9(}@FF=iZ4!}Y62=-f_3%(!2c!RT0-PY+TWHn+{i@uo|uexUm6?Wc3|yK9?gU;bC% z$J;{p|LSMv+NOZr!t@bsk<9bKv^^94x!}59*s-8OL~6{`_#0r1ezhm~a-@5wCQcb( zUzI)|G1Hf6oB6Xpu*V^$~M1O|f?eICi(G7V2a?JJU!C=TAbo1 ztVhkXVmsQO4w(9Blur8Bs=Ngb53cC&iS+G)A+Fu2GzX*!-6n}&N8bWR=={Qh7LY`N zfO-jnB6^M7>Z1mwX;yll9<)xE8{ z?4vt6o})oYAR|0kfrC`R)xfaD67X?Fqz8y&)1<7-O(2}nIygyJCZONrlc|6*#00{B z>*Qxw`ULfX(@Mnr#9%iaouCo!EQjyp6^^nuS$`fa6}?x4e7Pl$c_&_fhSgpb-LO zi!2l;K9~HKS$pwNyr#V20nNU4ubVp^y*T(_eAe7*85IbBoQKgNBdRJp55+@#>;+dZ|%nSNzg8&Bi{({yq@O6fa}}6(d8^hwRU8m^YGRU zhn!(#gwldm6egGZ+%9#4Xi0m7r>>tPHIT(_F6{tLWkt(?iRT~@A$)It9oy>hw@bG^ zFBG0n4vngw$J7QR3@@z@o#5o*@q}Q^Dzw2=#tIXWx7uQ1wtxo1$c>*&&5~$D8XpDj<(WBA-Hn4v`bwl8n;~0>8R0s6*_}frAm5OUafR`b3T` z@PbX6S+Gwrck+x=Yt>38ND%%TKR%l@ze3+F0L~*hn6}_F%4V7yafau}S&CUp8+wpU z`q8k-h`M5D|Iw%0e;xVevdX08T~bs9Ci0fG{EgSpOCtm2C=*e2WTs}5FdAfx(#)HM z&2>(#ou=Qm?bGguEUM-~mzF^j z&d#G|+Z}j;>djZ7LlSExFC5Fa05DW-9pHzv8@)FC6*_V`xVq-r)JRm|Gu+fnf@Y|pwBFpJgM|wqS>o5ad1WHP^f3Dj;KMBUd2yhP)nuLX@!jv?YZm=BX4J}D*BpcVR z5%!)T@~{MNwbeoQ6=^K!?T*QCiciRh8+&IZNtPYoo4R6`ZH@gk)f~^+zWI4Mhh5-V zZW`erxoWmud2l-6iDZ9L4nzsb~BACry)6&J+W9D=xv}Gwycn&-nquA$a6}2+4sz z0V_)BiF7L7CB~3ty;|i2;cDUMqG$EimV6(&94@FmB{&6XY$~pHcu|t zUR#IR!_A}xn}bQI`p@}XXe(m1#F?vA8?HK9dNq;Awj(s&;xc-B|CP+1RtA^C*O>V& z2SI$eE(!e(m==)0!J<9XLRc zVfl8SFG4VRz%VgsrU7TbROMh&(U{mU?eFLJ2{23XgV0qu4d|onmpn^uxyxaht$qFh z?K@x;CuWq9!RZ85VNal7$yZj>DVdVq_|B<4F59EEazd55hm z+c8ZEbpp`Z4sd2{Mj2`L#>`8Ht)2(oIW5cy75t31vVOUGyKdX1v zocZ`is9WG8Tr5rd_crsyyC~Qq&!S?GLyGrx(d^E_sB#s#*9!a9dC(Q)MR^W-q4nGd z75>N9)AnD?pR`TP)X=-q1r6HV=v37($hlzgP6!=4cgY3P#lkW>rcY58?o*!8_KX=QD>Z!{uK9KG;)~ zot(If`8So(&_n za9BlMz2@^C;*nEK9-rWNQryi-2$)@C_}o{i{ib={vwgzb_6nz+is*f&$Purtxfnbv zo~{G0b4Gy6Nw%whX>w*DHPTm+!{Fi0zv||9Q@*m3p>6yy8DA~6o!U#sk9KJS0buY% zN!Yk18J(DhmSF5puyj+0o}Ad*v0r-Tq#0V0JVg&vo>w(nRJhBqZvj}WJbSX!RlgH^ zOY*`#^pB>{ybHVLiS}@XrJC6dR>|%Y^!<FsoQvoG@t}h27Go9h>XCKm2PGS6@$h(6ft;cC&RE74Q_6RnSMhxWjYGr+hg(ngNyOy`Mv33E>$cj8BXp}4da zXzoVfEod%f`zn`~u5)dLyE`ok>Y46K?)Q zP&B|*W<&o{zMi-@#}o~l{;0U;mZ4J9Uq^_*$d`+O7des|vTzVn>MC1~$5tZN&;jQR zQ?F>WtBZO=)2fsNS+oO_Hgh-hu@l4q=5^Z-8V&7^#H43sgkCso&_vhG3X>m^GFny< zM7apGDFQ4ns*9oQWX7lgFpSE?gNd+#K-oeXvJCzvdNULN*t9#!VLBiKn!s#582Q;r zc!fZmkZD*-;tw$PTokgSGk?`456C1TSS)0bv$RS*ii=zg@d>f1JIDd`dd`xBNzlCS z4%s1GGKTq2TQOhF9f*-a4>s;(f=%l=3h$h}#NRgQRv;jQ0&*neq7PiJktWlm0`NNN zfmDHKp5)Ne(^CYT95R)Z|K`uHfd4cLRiW*`GFo^V@!NBNk%wqvr8$iRfdw}vQ7M86 z^-BBAVff_qAsEI-ekbt+w6l2vvk?a1@tYWuI&TdQ)UQ?&@dTyUjFU(FA2X~B13wR7 z4~BHJB6bZ%Fc^LAKz>>NSx$lc{^K)z=l^_x1DE9!?SoxKw7AdjbG(+xNBhf#<+p)D z`%8>g)UM`$KMY|<^hdk5@!o$mZG_;mjfq(;<;5V-NVFW|aajto3E5UHL+Vn^+ z&3=L*xn6fJ%CFU`LMOSD_lQWft4WV-UJftNI1)$u`3=0>fngZ-|9(}YKd)9e@uB(9 zH-Nvhj5IO(`5k<;ai@D20tCsuQSbCI55)s^ng}G#^}Td%-K^Kb5#Vg@hzeR%ccLPM zP;mBw`3^YbrWyQX*HCKi(@eml>x3O99V|a?aP|Op(m?>as`imy`mrA8b52z9F<^oV z0SUnX0CAJPe}&zEFd3`Rh}QLk%a(PT=<-(LsX+to&S%=AkGTHL?ZYVXu%ET@hI_o? z?C2R7G&%bbITY|9q=NPJpN(151|&`f2A!M6O&9gpeO-BV#N{!o+&^1MWRN~*Q1~t9 zgNB2^r*Wu6Z~bUL3c(6hmqhReN33>s~! z;SiaX2^TDH4!21@Sl`HrX^OYT`!mg(7U5DpDq;&^!6dPY(M1wvLYum5=CuNV?z=RY zXMRua^tv0a6tqFQAQrlqE5fuPFmifggy~k4dpmXKG@Kl zURd!u%1~D3#jTFaFrZu!W2>*mc;t&fMdALCgYG;T4H6*NQI?xuZ)3!HT#I4dD_hJ< zEgqTe7tjX=B&Hyrn;e17iGW%;?#PYQ8|lvu_gTB`2&+au8D)HB_H>FR5P|9BVW@1@EVD6qm$*jVQd1GEazSR9`)z<>$p7RJpO%>F6M(y)j#`o%WP zDKZ|mtkuZ#MCkhnG_Zg7M&@nw^o9LN%1Lx@b3n=t=z4DqAF31WhW&8_2@|842|##l zZJ%q~q}uf5#f%(Ih#Fi%vZlyib1|dIke;5tV3YGLd%(lAD>M7W&wn{GG;NB|(|)J9 z=6-z`cgDkZAJ!BVRX962ZQCBjrpe(SGBMZg4adaRm2Kf?G%+xu(^~Z(m30FAMv?OZ zA_>~JzDL523K+4e(=RM<$z74||#Z{JPt+%RjH2@rgCO(UwTQz2*>nx_{lJ%(t*_R9Y{Wx_F54I=umh@Fc@z26ejd;>)czfde zIbFg?+pkWw=IKV75kN2`$BM*y<_`or-cTsKuFFAEOYn2kraRdz;xa4{B-ggC6|!8M zkygIo+;}Aq_*-4hrt1+>hjkgI@Os!+o&$n^Nh1ED9-MCC0=!Dr;Q-v5k_YqD6Q+=K zV6kP*_O-)fmM-SH=Tx{u+T#@OjBL8}mz++o9AL#bpYP|_6uweYZ8?yV67i*1;p)F zFcyGXWjr!@q4uvi_PW)5!#TsZMf+lsRa8@6HDv_C&HlvoJ{RIwnR&qB`+Wvry(!1w zK3gC$EIt7!aR=~UlrAg{<)j)6G;|7(s|+)p2SPs)$MnmlZrUMiQtPHp380je-kSa{ z-wEs)Z}3GC5U=RqY8f8X(VAdvFG%ICNBY=Ucz5O<#8ib}2KFU@L8VWv`HInS zg)3GMFtjfWWp+9*_FS<1ynBxUFuRGkgLCfC)VeCwvgc)A$9XMy$+TJk+oCcN%~tEg zn3zMt&99W3qyV3BVt%F~v*y2oC$a9LO}V1O?#Sg8M{=v2#C+#e^$#>NaD@dzu=^@zjB7zt;4`E1gzc4jKC z-4kAwkcar?&!>spNvxU#(uG%QITHio-n@LU6;65Vu)2vQ^;&+rJr~VVkb^)Suw+hE zOHBbVP=+Y$yEEGOH!b2TiHCMsBvC)wQ&T)u*bOFK?$Al2jm5U5fw;Ws6+Z#1;K6Krc0F6J zDQ37nB9yxkFpH<65m2NqpqNDvIHgTrtwLDp@wt-?M0fM9r!*)m`$Yjc5Y~3 zR0>!lV!*9^?U#(Pp9K*ol_UH-cOK#BnoTKn+M(w-B0FPE++4t)7y})xNDc@_osal( zU6G)OP{@Hi6xMZ`@%NiL`x3dEqD@ZMuL5&+_p5r~RsktcS`Jh6{3kn$mZbLiWR?kE zK>BlD2!lRUbcL<^(tt=dTnH`2u1}4zCR!EISsn|r*#Yow%sIs>e)EL3RhfS>A~3Qt zpXO)S3Tri&ggH(-O2m^Y85F4$mD8Ak=L}gT;2SS=lyE!m3^GeOnQo2<14ffev98`Z zUWO?;!wIU+xc{@&{_J%ReYhY5*qbnI2t0kV#LHy(?N}1A;%6pW-V8^N_aZ0-^Yqi~ zAsq~oQ7hq^g6*{n$*e8C(0Q^+x{}p(wLcPb7Wt%>9FHG51YNQ?TfgLK;b@RFI;E-I zBE*|J{Q+>Sr%(3gK&HL=a1J}xKy*QHPmjWCK;O{i}_2clw zk|Bqrw}&MOvpPw_yu-AWhok)>Z2>C#{?3+CoP9a!tVt{QI(X{J8xbj#*lGyu+!|OI2O&h(NZ;2 zM>!NX#`$$2Z~^cfAJw|e-*W-}_^!lIv$863A5rV7B^yOA=B1efAMu%A|5RJhlN*xu z<1r+fJ2L^RBYuGO{LG2AlA@Wji}L`^+ET>kY}Q1CPFr&GwU25g*cDxA=G?G7`a2Pw z;LAI`mu@7dU1ujCTTV1D!h|`w<_!RJq$V3W`;D8=PKo)$xwCDX(NtJ4j;2ZvN^jlL ze>aiP&&SJvl)O>2vS5)Hg08gxV3+H|Y6cAqXmmJIBl~L84^Jp**r?GZwy{C5Jr#mr zhrd#w{NjcKtC|RW>W`xr8&MVjbZC*?xlnYYv)IEK5?|8E<|GFCMyXqun+!BiyT3We zVljRC*T*HlXYU{@h#=mhPyHLQ%?CvYjFXh6MWN0L)5BKX&7AcJY#9`05ZSoXmW2he zM^(E<+*~`lM^0vZ=$&y1AzPngQqs2V+chp=2H>zfqOJ;!0DaVHdW~NXci9&|-UqDL zzR|BnmX`H2p*I zDvNbYRx2|Ufij05bg{ETh^hhCVv5qj^U)w#lhiy&qk^0I}1Oxl6uwB`JeZD*(R(o}}u z>q=tQc#2&8MEnTA{wl8NlzkKG6O&n#uzOL@=j; z855dzCXbaL?{w#O+OaTeE*h1AM}zCJX#{whd|l`2lMaHVfh-n2^6R6w9H!$DBtG|5 zn_8sfEuFd`g=6Sq`l}7A*C*6B-zd%H{GN+sV|`yBeL4n4N_(BkG$m6nA8WM3K|XL$ zaf1pZ1wW384t`EY+(LXzGqj|0?rxGgfW+yGDrdX`&U#d$CEBb!Fe{E(3m+3(|c;YTupaiS-u z>nRm8aU;fC4ZK^`ybN`rg`<=%90yAJKw86iAI;FW7Y(O+tRCz_S<5*Gw(1_1#JIzFnEY6K}-~{hjH9fce zAuk@M^tXPvAMy##i%|KIVR_DlBR79;2Hdk8Q2>aPM$-&gRKRrrtogLq;!RYSj5N3F zGULv+bq3rA4|;@!eK?nHVr_T6tMeRpkjU^|zkWo#5BB$T-NC>>bAa)ji&?3@o0}?v$g|N;9y3M>|$V zHs9uba#Mcb?D~Vma#m=KIQb-=Mdtzo7DVDUi~`*;0H05Chc4qnw8p2Z8*t8XldPCt z?drQ{lLuJ-5NtJ74_GLXi-Vbl{;TOzg-~kf*N-7-qEd4Q7lx=~-PFwhK(<$C9Ln*I zsU3UX44_rDD-4*#;t;AkCD9!a&dz7?(R=%TWv9csc3136PJ0*>vFco@&vSK!?DD%I ziB$ARixpo4wH)y)0=a*Zb8faib#7kXOX5)OL_()(2^{8~((~WNU~1~A8|%%qBU8Nt zDbu-%Sd1d7grxRM0o3fIRy&OZ%duu!%nJCjCjfJ6Y&q5H>@E99s;prMj_xCXj>Y+n zVl+LGB-&037>V&hH4nQF0Ts4daY2SHoJYnq>LO3|FiJU|Q-HucU$;PPZA{IMRn-j& zHIVrPp&E4K-Hoo2X(V)5i8SKWOV*c#`&_^oavbF@EVsU`NVnIuDlIL2baxYLpz0(f z3VevA$nq(I9X60&&)QW_Vm79UGdeTY2+OfxcC7K-P~MW0MhWk`@zGmL3wE4HOJA`p z6RI!7Fc`HGOvZM7Rb&UmR2ib5{b<@^ys9)lt<`C6P#-lFikx!`!%K`ry-$p>*Rfe6 zUE&bwrxdbi(sHvpBtGpWl$FGim1b0Z!X@NKjdd`TI$P*)Wk{LE4$+>sH{yNAvM@mm?V!}zh1T_U4 z3AFz$AlY_?EIIN-4*&Z8Q6GEj%PbW(tQ3c07B2!QTj9fYb;0@bCgDU*`K>6CByzh0 z)({ULEH1vz=5{GDFX_bwpzVeuh{+R%$^!%vwHAlluLhZK2V%TqiB$z8AMvZB{y2_c zWhQoDMF9%rb`%s8jGz{+V2`(=2T4NqV^$t9{g<;#q4({+-F~Q=h%Bh%Y;Om~2^VY` zu}P<5ShLamuZPjmei%?&ut7wd&7hEl0aZQ+_?&xQIs;JO^O5Vskz|dw;^D8y^8!=) z+x<9~f!>?adil+p#+lmXp{qQYtP%A>Ee35W1wougO`qui+ZM|fOM_GsO%>#(I#9Ul zih#x*$dH*a=~p%)IjuI#tdI{o(w%g98_ZIrh{x+@Rk3hVVdjbQX(IILpnW`0uhsEI zKp7(?v!mbj5ceOF{ggw*2vTKggSQg1Iy4bF@a0@lN=60&;?zG`8Q!JA{B--3R~46u zbwMI&{;jjXOipRAEP9^|W7zN6PMZdiPJoSjGk@2s`fm*#t2hE6`4qMV3Xx4o;TZj_^b_kPS3;nDUQ)B4 zwI*gtAgLHIphO7~$;-7)KR(~>czR)x#3Zflb$LZQTt6CoxYr+c{NYC9e(t3m&)}N= zC|17wRuA@fHLGtk43q|oJZjv|(yKueZm4I?AW2uHk6x}5OOCM8bVzz6#YC?W;rY$0 zS$ynSe!=?e1arATc0~IvjXrx;U>yCD37Ti{9hdXzRKq-m;ddg@3OSE>vv<*g)X6Wc z%Fm-_D5$;x9Rw)1rLJZ^(dCW%={phd?A<9f#}m~>KuNP>+J=?EXP=jcCwY)< z1>|-X_FR#{(t_H@vrA*r?e3UO!;oAd)qX-uI4cY>X=KuEF_mW!iRzcnM&4b5Hjd0V^IbXBSk3j*^Drktmo9La*Vc7>5BOV zL8{qU$%n{-(`+?c(Z@~gY{(h8!w8Fh2W!b`J)0DPPmiulH+{x6K@tZLraa_W`Kcid zTWJDiH$S|zC`N8ZO0w%ZUlKF&tJc29^cBRSG@?udUcFo`q7yW6h5pW7w+(}I#vGeh5fuZ4n*8`!}YWmg?yM|cc5G&Cb{P6ey?+_Cy z&Ow^WU*nf4HY)j)%mpBMFJ%38(Zc+#4%KN#Hr3UW=sS3Uo(xzJGR^fEY87!a&urx| zcpaZU{WIJfbE%iMViv$7SZ*|p)>q4oSobW_Q!qb>wTtN#;RxVXW)5%Paokxc7KKi5 z9JW5%PGut5a#941P|A*=Yfap1*QKs=BvqcT&JTZrDJcUFmndEj@TgX}7xOOm4wy@_ z$hN^iD_t6bH`=AA@*U>ljfKhqy>y)=$+&Ulg!W%cf717J*X`rhjaKY^Y`m1m9<<~f z+rQLVlSwO;Krq1Km&008bhzPk)^d-J(+8?&H7Y)Ky+paY7^(gE{qz5Af}D(z6A(u+ z_SAe5vzVcatIVzwoA<8hj>zBZ7Iyjk<9(%1%}zeOQaagCFOZs=I@R*d)>f}2)%L0c zYsIa%DRQi0pP!l)r=%Qs92Ow3hTU+pSh%mi*P~OpluDVc8#cQgdou4-{(bkE2?>p* zxWqWQ>F;*`S@QC~*AM?!Z2;|~|NZ2@DfE9QH4-1`EZ-_?Oi(bx=#xa4tLquNTUmTI zVwo?pXF1Nx@nAanvv}_Ri@moDi+YXTM$x^+mTdq^ZWTc~rNaWGrMo+Z?o<)jf`A|) zE#1uwJ%~tm#}Fdj&Cr}RxcB=%?{&VM>wGxZ`Ecd~4hZwB=UMAs_qx|wLgTe7`88fo zb92czx3^zAJ2&Y?vg@y`#KAlt<)?2F&YwRbsw5jt6A=|v)a?D5M*W#zU@ZL0U+LeT zp1L6HD$KD;)s#3>gI7k#`n!GM&mcB_i-Gk5RiiEVFk4Z#t#*R#fJkj+ef?IwNH#Gi znfxNVEB%9mHAAVA3rOvnRPCyx3SQm{%a&a$A3K(C_43{No*@G{PtQydkyvcGijvaV zuL$nV7uPcxDg`BQ=i~l_jcJb2k+w{#e~@dz_;lC2dXv&>{+Qs#f{c|%&go8Y4KyO@ ztU~dPA>FdagU{~AsQ+HCCGOof^5mQx@fz0^nNTW9N@i$uKh?-avR}zH1jPiUeQ^JORIy1TU7_t^_2OmTI5wZcQ}l70#a=t`7WxohTl9bnZ)H;-v2JDs~Mw z0Tol4tE~4tRt>}3H#}Vb>UXYsl=@#~%*7M3SF*c>F=fn5!Tz-t$1&;c#Jj zS;nAMMpQJ zp|nYetDC~l4)`YKw+;gDXV9k@WrpJ6oSh{(q;4Ha9FLpo{)JSwn0A;-ufDwb^X2!t z7k4NqiiQjsvefso*uJb#*_w?8Q5O{Y?My zUPVmKbwr$8$VN*QT8_u8I@7fry_0*w!LbBSPS)%64U^$?Mq#0FoTk8)tJixrXFiCl ze`cHFRg*-tG&RZVe62xQsjn5Z*S?@JC{#fjcRIS1RWiR~eE2XK&O^~bs(J*&_k@Kd zt70+v_>Fp9pa9r-m)7rL#rOq7|v8$1`g+*gUwB|@GvDhCMNN0WyVOVC^d}3 zf?QsfISG~6qf|l|`Vc_{8&ify*eW1XDw26Fv%Flf&Zs!z<$KfP3Pt}9A7W=Mf_8wM zkbm)_*wyvm&b@niLqo4}rDVcub-whW;TlwjeblPW%76VzQkdw<86ADFv%O7AMfHkr zb?gE3;+Y{1%SuaoMjt`*nAS9tDl<7*Vy?qjNJL6d)b!Z{+1OGUpE|#RTV8K`gn#Wrs&9Cy`?Mp`jcr^DYiMQY|fXuiZq`UEL05R#sBK{=`dVkm-Ym$wqSB&eChMPZ+vWnPUbV zK>hlq#44aZD|Yk&?sMR-2?~z;`}=n-_P3G?QZ|$>%*#K7aBg1|}i% zPr13%5d{cGMeS#0<$caXzBtF_e4L|{SyUua|A^3RZC=4iIr!-K7*=;uuKHl}MCah7 zXO2?#m4LjAloSo}xG@qEvQTIi{NTZJB;6C2fgP?VQTDVCl^GckY$SpHA5@dVX~nok zJHTARQ_RXX|J2-<*VUy{&m1`5d)=H&aH*kvmY0--Vj$$9ad^=K*$*FV=xB3ao0_IZ zM@!k-IVc(!l%cFJe+vmEsFH74tOl1?t!d=vR?GYN7-r>L$+?L}oh=?PzlZuoArKrVlW_AQqX@P+Ob%EdOp3m+$G+JCIh}qc>VGm7N!3@x| zbWP}jc!DlmGgHppy+lr#&4c%B`*A)0T@zuAX)TMT5mPI53}?I)5-&)!N>9tE40{ZQ zgHZ3#Gv;=cZ>gFgR$lAMMlohkixCn&sjy}h&7}Xlb7UtYc`#G;5P=})bv%lVXb_g! zm)O;B>}&-a8}G(Bd>rbLhg4ANUvSDl6+S-x!|^aPBS+CU<#syLVkNUDLavEn$~GS6 zAB2b9nPV}KRn&wE#!gds_UI z21b$Bj`Ib<>R6&CU#ZlhK2khgTD$M9cjFT_HZyh4)GD=5`(2GR^a)b*&Mh*NL1+Oa z)fklUIXgRmj?R30;q6qBTH`M1-Fd5Qt0N6J=Q7N9T}@2^$41WZ%C!*_V%|a(hJ)pG zT5t7+ zK7c7%nvxM5oX-#rHDI}G(dY>)$Lnx#LPb{Yu2#^qqyi z1&PhA9oZN90h|a8ed1M8q0{Tv+u4w)?CR>?JTE23#E!VuKCG5&gKmaVT3Xhz(Xtn6 zPBGNhHefr_iNM6#x(Ss7o{>gIvo9^s)OGWN2OCMg6iOGVwljc9c+5^efwK7JSyXgo z`}7E;uyebi_LI+1U^T@x%Pr)}@{veQFV{o;evRuZL9HFMeUqIs3yB_;_Jg~D6@vPX z@VmUcmEf9k+j7ohP8x%qD%{+80eu|IC7g)oBFG(E(_N48FZyk7d7ZAL>`qC?S7qc2 z>^#a$p=0w|zq`8o@%j>_0NIu;?z0_p)tpFxKekHTIJk5m>qs(6YTB z(mPUo$TU_uXX&^0@OmJl>r^{|0UL67@o|1ew@<(@uNSL&r{|Q-L$Bax|7ijI2A3@I zizju9Vcn#EPhxX%a~qByo4RtP)qZx_&|`}<*wn@L`^O*`6t+=g+=;rvo>r97-ChO! zQsvArk55YnQ=j(fo{tOCDa{Ql?t+w#tVW3c=N=!9nuknbp;_ zO@FigJ`PFJd7brL=p-TB`wbnf_(1cKEj5)4hKn&qm?sh zl&u zdt509Tcj5@5zZ**^P?oh#3T$0)fBa~l4S_UNKaKLPYrGd$S2|K0?ylnP{|UxN_h8 z&&1m#ZuUKf0$wY^<2SZMd_K#mrZl@;^#Yu8!~%#;lkS5ojs6mpanxN1C% zp_N&lZ(^DpJjhgu#wI_lcE>6_o}SKOc)4njr=&*U0-ywf7c323w(s%ueli z^6MYX;1=EV+*~qE!ch85^JTWX*XUsNU8M9(lekxYg@B;DgIpcq5tLB&wJpcp#}|L8 zP;^cCxjT4qjeg8vzVCt2&JMwl&vzq?C$G2n3)lT{p$vebrsi_?*s+*96ht{`vr2IS zZmQ)j^#|+8b(@>pUEnyVcer9i!y>hl1S(7E9cI{k-v8M?Pmv%kDjNCVVcpI$7p1b~ z_O0@Ya_PeZ7gtx%ZNAJ_VjSF@{`10x{nq||Mc9(OHjD4X#p$*?Dii1g1sg0CDuk+! zLr6%~!$Lz-E@D@^LjQR!hVS5n&B&_II(HHzdKe>aZeGcmqn*nbGf2nJ{}Q}hg)^<_ zy~r*5y{%qbC#Pb!vDCu9SLjbSeA{MkuDDsJ!*4UfWPm3esQD?Gpp2p-B`+838?B>V zdB@{f+qgh;OG`xnWAS?}f{!!=Xr$V6d9ByWva%MpcN2uVfpe3%A(|3vazBBO-DcH2 zZQSkj6F>jx&V1zBAS|gXm)7N-obvO+lv{i2JhWEgR>rI6R;AP`ITa7Fl>OnGW-H@J zDRb(NeR>Q z&`3Q1Adu%#@*E9J6Sy z{Y&O3RA=$Tk-t)^R!l@E1|y;Ev3VcveO6hDhU)MI$J&IB4oh+#R}ttgtW))ZE+`fCgK1KEs^Kt}Y%L8JP}1)rc^s!kx!y z99iGkI1d(Qz)}_9`h^Sl^Tf08X72Lkaq(CGD4LiQ+@Ro1d??y!R_FUwP6=^m>@*X0LMNcPr&A zq$_gD)TWVf+HOt+A0OXgy-Vy~ApY@setfZ8K6Z0c;pNNusu8}aYElS`U?pK3DDK>` zuES!OzmIGycx-RXnVFi(171jaP`5H*Y)JSjl+#K)0ZaLNDus2r^^x(`*}@;CW@EE` zBt}a8afHhfaUd=xXJ{A*!9d!mZ%j-~-3*KzlbRap>7fp&XPb~SHn?wo8T?D=BmEj@ zD@#kwFXxS$js5ZZ_cl15L@h^XSA`{mn}uUJaU=9!zkcJmMnWpU%vaepiGt^2M7SIS zaahL5`s_s#GP0h$ILz|*yP@_QdMFVQ5u}SdF~d!(ySk<6ilU z{9LjxUuN+0lWAWJ`Y5xYB9GDG3f$0$t@$LdHj+m2h?R+{g|m9Ty^4bPY3ml{ntM&9||KKvN>JUd58DmvaVFYU^o ztD}XA_wPT0i;|P=CdAklyS$8Kvo+)(!L8%Z2QWs{Y^uNe*3u#gqIJ$SPE)_&>Tci` za5J0zAp_CTR!7li&$>gqNeK}4K)yCR?T?zjR;-Y2PORmXm8N4O3Sxur+;1Bi&9<6w z481G)ZM7QimY>y6T4P8^C}N6~LV?+VX12zq<8;l9jS@gdv~n=bU5N<3XnpJUue9Y# z*M8fT)9o*6k}E}OPh9N3ULavSGwW!y*yRn@k;8A*p9g{m%{WLDWo4(VNyo>va6FTY zOael@i%33(ik8)8Q9m|NF*{;uXk!a7d%w)-jIy|lc4kL_vj)SSGATZ(YRR4Q~9VB7X+H*U}Ix9dehaqlH>~q5=DQo_*i3M zAu}r{t9Rq}oT92?_LFR76T=oZA3s0t(FO~QOezxjA~~7J$IoXd@D)#pUu9)zcv>1x3h8S=;tUb53VKp-p50y@6ek~ypgD7wAgN>5)?Ws`z04Mh{A4N2K)Ci(= z)-|sEhqJS-HU1j$)qPOYY`igf?%pP4>XkiK836x}1-ffxav|%w7wB7P|*c~+lAhtl-$xoeZ zWBaA2kC&*7=V;%Q{N!l61Vc(txxKSvuA}oBTo7s@aE>03s+RjCEjf>)(#%Xhuj_Jb z5CtC%K&;eU)x@z%RHsQaG_Cc?Uvb61$n0*e?k6ZfP=OIt5cH-8^Xy0E&?53NrwB9TsXymZg8E9DZb-4fF) zQ;%c_2&%Cs&lDNDN+9B^YYWzqW3TKL-lMmE4W?;O-WKo}Bx$f(9Ya0VhQPiaaB|ppyMii2z9X(j4F>oZlc3&T@#mU?!_LRAK(>XSn!MHK~VFClHjaFLQtp}zc{t8*Eg z5E|kumdu38${6(ax+MTgzbjW-!n9u}{R+LJKA)Ab=a1gl*8ePuANL0s+R$mCNmaI! zgS`XSrDht6Xq1=9t4}La`x?eq5%=Ty*mWuH@p=96hc}lAPw8&yNcGY+D4@;83hhY( z!~z%I4|kWR+y@t7FSZy4Xi}Wn*3vuwAwoHIw{*H}Gce{mqg<4c!JT~%1CQ-`^ZR;w z(sFXn`}Jlsg>A^j`x>*D^*t|lW)(%O#Hq!^XBo$zY^H>yHKgCF8b_+Nb5%DCUm_ro zMQA1i+Aaa3>W2UTrm9a> z8Yy-=tis6Lade=2EpJ{4upS1eov{AeQz*K5GtrJWEhZNrGz6kou3sO}K8>_$?(MC! zJhorE9y$#`u%zS;C?9Z)x|~Qnp!YYnw*L0m-9Z0@$-cZ^R?WCoUcK+z**BH*BY`Ha zZxHEl{h0_wE?z~EGNW}0XT z@~U5Zdams3TsIl)$h{$20ezp~B|pVyiu?B)VqtTJA3|(@!Vg^6tWwf*!>9}miO2h* z8`5te5K9GtefGtQii2XIaG#By_!wBP57~c^l1fuu>$P@J`@V6rnn-TBUpBrYw!Q1; z&rfxn>753zLPI~_CUQTeTocNIbPKR~-QI3ak{Cz#KhuGMgr4$k&Xk3a+jgEF8ZIa1 z{R2V_ls-(Jjgw6%8+t6pRfAF=R+xLj#3={40&4jf*oAFwLYFTWjuaWLq#QFS9RB=@ z2gbM+;QRu6BpJ%oeCajt_@kqvCH4#LA20gj~^E(2irvZtZB?zyV{RrK=R@GwIDh6^ z*X_q?@k$-K|y(92oX_6l6!>&8vNF$)j%mj#->k{(krjK+kEhSzgd4` zr?fQh>cST_On=wVFYB?rr5XdVp^vDYZ^u{$6GUmzaQq;+rZJ>PG8K+n$+q=hDDd-L z79D~{)XK)j*c3;lYz6HJep8`hgb<;3?N<+iAfJL8UY=@EsuvuW`1mS!W+{dG!0bT2 zCSjw=R=ecex57+I3IA3aAB&h6_3+PA+e6GiC^K1G7AtB~s z9gbS`;}YuX>MFp&dX9rh{b0er#duv7zxQMPnlaVrhH@>ieoUQl<>)nw3G_1xiq*yC zWlK)J)kdDq^Lq3jasoayvaws|di3Ja7c z3xtdkYINECSqHvGPq<23`upp3YY^&#OQZV?QId#*;hGaQ$a^#m4ypr$%gRK2s%LWu zTrj0~06qdo9M&8y3juSSz8l0Oa56ORa;gWD=!Iq64HL9Z>niCgke!AxhSvS{R(qIV^x9Wt0#X8p& zE~{+FzMLL0*T^ll82D(%x!PIu6<-l3u}WwB^S&6QGfIrHn!JFcAVL=d8V7JLqj&dL zKqt_o9mpv}!^4O1f*xYVorZKQUD~oCH-WeV0y-OlIFc(8_?8G78ffYA98Mk{uhMY8@ppC^ui*jE`3ot60R;wwmVy7} z+jA#Cjw!kb2S!Ir;`l)zfdNj%wa4^?YroF=^~?5nAvf6mXpaZDHdz^~1YlwyQIZoz zC^llV7U9E_$@Q$op9*>)WI&opXn!GFt?+@YR(!k}@HmK^Yptv%-FSAeh>7bQT-4FX)Kjnus= zCtX7KL={tt=o+?*+!;T-=y2km_G?O?@a}v%gk$}EoEgQ%>QKmX{OUG=KGWdv^O)9S z) zP{oBd`q2g~^FS)%a#6FhO82hGX;_q?cl#m%*krLQr-y4^f>E)qtHb&8b-{wlkmX=9 z4w4EazB`|fqsoELo8OtJ;mb^bBn28fmcDax(GL)G8W>SAefbp}bBh=)5D_{o9VA=r zg}cw}fi?Bmn>5BH`R_evTz27_c=g7`6bhf={E|>0t<9J5o2yAT^gN5yy6YXfr*bNJ#0@5ZM=qYc&!MH-E9I zyBH!~q*U(W)Kn^DO1se)oto`{Q@TLcKc)}(~IjTP7~6H&i0=Hr0AtVa!9=) zr^Xp^xdF)h;4mD1^KZIWx z;UpS?X*Z$udi|&SLY@!6yPRUZPL9JKz8IIDwbN=`V}d7E9gD4-%?G_6BXtEzZX$p6Dyru6^k)wlFbKfwalu66L3w zn*4X?kFB^LVeP@T8L}Z;Cnl8NzC9^koqx-m% zuU|XxcH!Oi!q48GaE(p?d6BcGRPK~o?lq>%8EgWFK%+m`Sl;#WI6gimLyOQzYjx2a z2Ae@*^q^&mpac6Ci|B<5K7jtN+_+IBzC zzkh$e?RB)q%m^BlH^SSWy*w4u1{{y)^W%GaQo92*JIDj9C)#nXhw$)%Mn76ljGngr z<{k0A{9G=V6zj?An-j({Z%W7`*pn8T8F~3KLop)n_QJ7(%w#; zE2(M}Gg1P2CgTpRfy~}W+{!*&tu!xe{S%KN$&R>)N{o~?6vM|MjT(_R&zI zLtaEAZ+y@gi0&3pH9!~`no>~k7g(jpnaNdjlj3r6 z{?EqneLGh-Y2|lS<}4ho1{}BkDode$T zf9LS~Tlm1{-)&X?`~Ls!pOi5D`I13kT%^q^fPmqTaB zQJBb@|ND!UTpxcoM!~}yeg40zyuhvwFl%{g`rU}rz}*tu>ka0tXX)>6et(U<_Pb5q z|NQL#;ZHs;{jWPbY5{R{OAAxqqGBubV@U<5IWtR?nVv2KG%kQ1qVkH0p%DUtnDB7T zjEV|;kg`Cit8~<3f*2|g!S}8m$opC#3E3SeJsto!bpwkiRDp!+XAmG%oT4jdW{plC zmg8hX%6%DVv?{0sy1Q@UlA&TBY>EXtz(C;?RiPyiz&(HdZh4?{yDV>Td^{5;i5cX| ztW1~DO{~SKmzECxz3w)$|8B$RE;J;xhYTv5WJXevNCE{nQ+7X{7!KOSk6{o9QWEv; zh8W5w1GCRm05kyjF=@07><0|vKrB7Tz(S`NeB%i^g)WCGcH zdv_~$fP^?$pXv+`2{9i;1K%PjWGkZ1ncx2~co_)P!;e9Qpi#&_Squgdg85(v0vC?* zPjF7*di{1G%0)X$bXk`HVzW^%_ysMd_@M}L4f*M&~Xn$EXKrT zOA9N#|F_bJp(!)1w?QHQH7JOQkWf=rZDhK8nT`D_m6$qbDu(g2E@myeq(ly2_;wds zGokK;<3BBce~?zv>M8}e?fIb%J5a2s1G6UMu`@|ZffKiQ?j(4HW+I{O7gCmB1!G$3 ziE4b3SCAp;<+}9n-Zgw&W)ae~(`#$#kfDeZNXSe|qG#t_`}YEkI?INBGZA=r+IN7Q z3Kl{sPq;1ITN$p_B<0GH1#pNtc;P1vnv7QjtJTVtP6*gN2^tz2cOaR)hTd}k&w#^6 z06RjdylZu0g18{{*mDBDp@sQz2t;T-)XOwLXr`uy`vXSu+V9>H7ZVFjNC-|!j-0Qp z=Gz`EmU$Hlv}YCyr8}aJOSI%`xk-T6M~sK%iBgt($;Av)L{bF?sckpIyrPtR!9p3p zxta6xk2bfqWW~ipwVY4H08ARCrT-?w@V+tpXNkU%Kcr=q20^4#SqH@TsUJ1&1&Tl{ zJe9IzX_<#&QPV&z%DRFxMsz>>m^+C_2J2*pHT$i;+>l}vjRzb zX?ED}Uh@wOj4i^=O2WOi>Pm3K72s87cQ;K7yl%5zAw*VIE!~@tT*^lwN*N))(Ca@V zMn{KE!f7AkS&l7@l+aYBtwx8|8g>%dRJ8Y59a~(L^0o4Qh1#lPmVhjWc*RTB!J!(o zluHZwLJ#V8n$a#~%E0zRUgN%{oDTHH$GyI_pSADBz5QfhMt&6qI=ZEB<%w8SZnsH- zBc_T+Q@CC^EL>6NDi#QMP^`;^giQK>DChjH2?7`ZG1H5S4}`Q6Xt6hmNEpP-td{J{ z&?zN7oIP5$w(mZQG=8>k+bL7a-@STmI{|f;_5o`diq@X~W)>H-c9xWekq%ByuViKYA*(cfv(@yV~Gc5dHRI(_4@}v77yS{W`il z@!4mt7EY(`&p-EuMVk3sHh<+DT8&pJ;d_V0X=XqQYH=|p3}xg~7qYLHFWu|5J;dXO zDNQyv7TmmVte4Y$P9ZS_e-{W{ql{zq7-Lf7Z$sWX&wb$I3XK` zOd03{LFtDBZ7q6*Lj%C<&c`_sH1&<-fsRBiJenWT4v~WZwmttb9h-)LfCr9hfb@&? zcq1WbM1fcp>!Cc|4uLCL9^m3CUF=)9=Jy1NLM^2W9m*Vov?mo5Z0WiGP7ZmaFZsJ^ zFdm);NEQF@Mc4Rs(CZto19EEdxFeF<;jX9Pt}ljv@j_Ec|o=CtKQ-f^^cBuZrp8#m&RGsV%)ng zKmYgW379%P^|`sFWTd(L6E?kwm>5h7I$N1JGB`LAwpNLYd_^7J&oYRIXgR6nC_UX( zAgX9-UICe|o15t&>iR)XT_xG7J{@e4gAO?NNbP-Z=#_h>N9on}>Qk!Iz-a)Uo?<4d zGMpxaGQNLj`!`i(X=#ZQLO8CDW+fa=_lqHM@%4ORF)T2kNo*P#aVHF~pCsP>izc_u z0<15U`|dHUpV2`h9~omlePz)wH@5ETG($=s937ml2%)Tu3so!*zwF5jdU+yc+}!*? zeyWr!UcCV=uek#uLPCBSF{I!G6(>{@39?B>4#gycULDC%3cL$0*0_p3UTU8yV<5_o zR#%((rKg}`vVI+d#S%1GP{;yYdmeEE?~Bj7chAA6UATC0I35F-W>@C6Ad0cLg_CUw zDHz>1;dzY2zW=a9lUFQ#G`gzJn_Y(u17TOkoWQ_59VD! zKmgEAW7|LoSJHEGE~c#+k7@)#*19b#xU_W8qV+c(#$$PF^B>edyFIusyZ@(NlV?Bt zY4HF5=`R@six`T|p=%X4m#9>la_M|%N^9cXf5ft*< zdw%&2Nqo?k1_FSccg$7F27Cv#6;~@Xb$IiS4;YVs%?$Q;cO!>V+y1xO8g3w06qS@x z{aZ%rnJzdz&Z{lA+nxIzGMCwH82?7vl9S5$$6^qj05a?eVCH{IM-HiLzADt5*13hItkrCP3=NH7 zvK21twZ7gFS1hD`cAeki0{*+4=fHxC$q5U$mn35yu-jQBInTj)nOU%9;y~z1M3~a6 zP?$S`vaUa0%Cps!F?QNvWMJ@Px6tK#<2Pc%3iB?#!i+q$7~D2(dsQwRc?~WO#QOY( zF>l{K>+k1k?i&#_BsKOzxAjW~k)Iu(n@i-Z5ip+4m2A1sIK3#KOhrx2d>o)yxpKAD z00}%g6OQ`^=`7?W$xuj@hBT?LJfDl_Mu)C;3S|P$%N2L%IHX2M`Gc|4(9|g5=dmel zttB_9FfYjWdMb2^ooF%PSWGyXtYMP#xw?k+a+YCC<2+u!*ohNR>c;f+fL(4R2m|y0 zUaq8$v*W})Dm#jd@9Z3{&xY2)+b_?7qI~E5M?VC4Jw+|FbsiTk7>1^RlyeF6Za7t^ zALYnQ0Ro}vjbp^g$THT~KgB5VSyx^rAh20Z;;oF7D?<7QMlrwE*AJ-Mg}A{H^IwdDXZ`-a zCny3>Fi!AuBFJlTV%gT#UP}+quH%GRkgJABlg_~qnk`<%ooQ3kx)_F@Hun=%ZtR0m zE`AFo(4d1{AB5QS92_be63Mudp?lYS@AdO@@aH@f?Vw|0(^wivgJLRCNP+>7hX^Vg z@(*yGCgxU15DBJ2F$S(0#@(YD(gBIN>I0Bj(r-Cd$(8eb_QA}Iq_3-s0n!UUp&TTQ zn%+gV>Z8bE4Q+`^PD?YR97G+EIGLVeM%B(g(OYHJg-F;+l8rv3c+lu;d}ur!btku2}TUMgUT%AW&J2Q~8l zmlBekM>lnGRakm@57ND)HYF4^<@4bXF0L+*dCfjRjggQ;hG?mO;{AE<79QykmF%rYAz?X|%@G>Ei1@G# zj#*~N_QAq_ zPQ9?s8g}e(%&n&Qz8rzqTHhTgl-0!yNJ+0il7^OnE{VbJk2W9rO!JsJw$X?m&JdjRRU^zCzlkY*hRhC>FldXL9ob&Xg8wf>? zmkN)LT^*E+k+)94J81T{5v`P#Sz6uprr@FjPDdwcArnYV8gPybX?^EL#v z98ZvM&nXG}e6AL_t*uQ7&*(?Pc9=`#9~Vs!OH^E?cRx2bJtUamTC1vdrVWO?56W_Q z{>!N&dE8i7m;!WS@A&zXrMo-iM}x@c@F>nXcP4ts#GyhQKG@`FuT?16SXl`XGtK^5 zTWj^e8dZ)KH#gJn3Y5is_#n2qDPdw^QES0j%qn0wUaoIkJp7n8H>s*BdK`VOp|N2D zi+xB(7rR|D?Xu?d;>Fb&!Y3S@C_N66e}aMxT4(JaJebX2MD;mM=AtRL+H1FnZRh9b zqwi&hPf+qM43)A9_$X#S;C4JB!-J^)J~y{@#}ZUsBo}1`?d|nTs41Z{%L73R1QhmN z60+LCLBCI3f6K|=f@xttOzh*>C8|$nW}YYvaMGXC;Hpb8u6h3vL?TU-VFMDr{-4QF7~?!_hoq;8U6;Z#%0aB9UrQN zg0MviHO$%iNkd4xt8tnFcZeeR0_!dH^g_*fe4vW72ZJGiK#bDHhSfq+<~|jb$+%sG z-AXZFTY1gir*?LHoH2p@*~zcO{f);SByipQ{VI33vwHjYTh*s}dSv6{S|0-gp$4Ec zO=>A_7aAPneTt7i|5QXI>)|N2sSeAFBqt|NE-bvjEYrzzD(WI(ei7<4H6Z{z$8z^; zMcP}5$gMJGp5T0s8Pj*~&J&Su{rEuz^!DGZ_lY2Y)$&*&7ZGhFJ1j0W=0#K7yEn5l z;rVJo^6___FE<`c&xTv?jw*sIO$-z*njNexEI*d4+@BgM#Lq7F_ts(8#LQ@+1}ojSCW09t9y?Vv*VF!s2I!b@;2Xd zhBilubgjzm{mIF*#*@Wp{5%cDpPS+5Pu4No-woKtQ2KS7@pHJp-`$bd)Rd97WJRfZ zL)K?%bU&MHs3!8_>cosKIx+F4*6GT{u*gAf1TzD}+;&v!$6%SVZPi!8!q;KRhJGsW z%^ti$`}ncla!hOyx6k3`Rq_2Xb-%l$q)sGjAP5;oGkP-%x^>;Oh6=;kAI$+APf9n( zT+Tm?WSYT=17MwF4EZ5f%`_?KG;0HoHN8`#L9ejwUJ@xc_Va@K+-Q`8Mj~OZ>?5F&6yRdaNFt+GJ1t)_?vn*r-=r8&w?1W4}iwFHh9C zo3-ewbHIK&!z>^@l+#t*QC zewdW}koX$*IzjLz6b>Pi-(?+F>lHuKmF0m#2KOlf^n72V8FF)@o88^^*LlvEc2+-s z2|6B^#aqE%lg}L2Miyg? z*JIU)Z*#+Rku-XL)k*7%T}@oO(bNu?AQeq%Q(?Of3-_#tr6ud>PR-E=c}k}>F9#{_ zUWe&vB0h9Si)74Y>~JhDx5VdBv>S}pS{UO?~RS6~(YI&c-vtrC8m)1WA=Qul~JZ@lM&^L1eEF~WIyG}cs zxe?vj;?r8zJS|3RUTITRLMX-27j+~G7D5xij&kXweenBL>igZ}-?vv;qCUb*O_<6h zB5ar|Uk2f&oSIT#em=qFjo#YCzMT)wF0MTT17gO?!ScctEiJsT%xP&aGwBw<`FS1` zYqRq3)YtxjEp})X0efz0x&ke5g5}jQO>5)4KT2zMjzSy9hx%H)s*do%nJzbV==En^ z^7RuXQ#`cbblwl=%Cs^u0>eo$QtH>$^_T160guDtEvPEm95G+pOs+Y~lb^xa=aYSH zFEOy&aB$G%FewQO>lCV(tj)t5(03^*OOyW;7TTQ5r0277a6E5FQ&=rG<_o!*Sb}u2 zIXQX)LQ?0o&vlZ;%TLJ2(h53h}JnLREz~qNCmcnTJ1o|MuL|`?=3%*3%$*9_Zk@f^;I`YyBV`{ zAtAb>HBK~m!^5hv{0<>mS+4l_ewVJTJMm7~KhD4FeGb)mC8?uv%w>6MN^0@oC0rUU zZLaNQRYk>qzVlC}Zr=_I?=P^?_m_`>tHa|&sMSpSN4L7<;nfJ)_sH(Afz|s|!gS+v z^GlBx?39!O5)M*zp&e`RX>fZXcihxYAJ0Cj{92``MtZes9}PRfqGM{*gmgrM(8)9*f4h;RfpMYZiWyk% zS5lg#IyDnj8-lQXQ_}LLzMWL(_+Pnr4PJ7}6OymL)<`74F>Ij17n-rpHaAj2Hz&o9 zK|!A*wZA9U(YRo%lVPTuKiDF2k5Lce@yx@Gqpjd>45rhoY8zi9`7MMoq(L6{*%c4q zu-#o<&!sK9V<*vht6H$R0jE4z@HLC&0-@9`o^s*$etw&Mp9wzyMHw)>T-&vNiLrg< zTJXmTg%vyO$=Yyr_{Wb5p8Ja!*xOs9#FUSysjqyK)g3fo+n^CTq6S}0CTQzFG;|j_ zU!U%nYk%Dw3mm~zUb=B(df50z=wCIy@O(!`D#4P1;8Ln;14FRit<8O!Q&JN{+g}@#j^a9q? z(fRZ}$rkjn-%?v$RC1N#y;ch!O|bv#mR0Xv!NT-a+>7A>;sqN-7z#?f%Hx@t2m^cj zj|dDK*|Q4-1O%Xpd%#@tJ}JpIU0mZTW3$_I6Kz97gUfRFMY8*k-wZwJKAJ48X`472 zgTki-tsa{^aaX&j*w`Bj?i<72c1jVg?euBr#HgL6+b)x>GTbOXKcDqw_KSD#-Anyi z@R8j(AGiOwcN1Xs!X>e>bFGIH$J=J1i0|C_DOWwe-k5%mghclcbuC@zTg4CVfkzD+ zCl?#J?RKwFlJnL!1TJlC+U8!{hAO8idkuhzP^oLY??+klQeB;97{l(e8W7C80}Xaa z@smTG#s!{BOXD81y2EmeN4(eijb%$7mn7_bYjc$7DczmPymejMioInP zOq<{P{<%RQ)p4W`ppqu~$1qBUu=D*P8yhDBFM4>?BM%T-ET0$Q z=jI>S)4ipa9cs}WR8;?flRertu1RuGA}sY;9tshbw!8_w82I;p)GBTSYy;IjNt?R?2u^$Z$ z>j^b`c8ZKHolvyMg#{gXUKk>?}%|n=4tz zc=kSrgj{+0Ot-vu*S|&W8oovrgOs$i4H$Bff{qV7`{S?5}+f|FwFoLI-CXQ{3}r z=^1($tSk%3b&H9J!ui7GwKkAmIh|SwdADwk;z1Nc)v3T{VeWKtq*WDmvFua})iGKF zxq4V=mX1FIpl$mVykLI&{D(ta>aJ>RnM;GZ#m}@n7Z@pnf3J~$xaDUAe_P`a;k|={ z0vKa%W=;y}zDE{~_9_`=DYuG;y~C!R(|6&ICl^f9AR0%b&jB%HYPFV>Z}kQo3f!{T z5hq7SedGvuldpw^h8?VuQmRHHyJf7KKE2fNwD2Hwc+K9}6aV7H!``{&3eOG*l^bZN zFI~B!(i7^dsadVUpai&j_Ie7SywKRNrW3PB?! zHUen0AjHRA{bLefX;?h8H?Ov=@9gO69~|%mJ0;Jw=@$=6j`$it*!`F>+g9OwRxU!v z+4;RDAJ^2>RJ-r>rN?wxUrTbLKT7o`j`bALS#ZXvOKdV3q31?iuEs9~ElUa>&EK}Q zlX#`+C14U8qx`O&v)YT(ZI6{z_XHQNP9{$zd`&LC7!yc%y`tRhG2Gdb5(D7 zxD2QV$PiP+5vo|2d^w4=d?jUDg(V7&iV{I+-i9^`DX6>`%gYJHI;j3w3eSb z-98k!2a(zcdK9}kQr7?H#fv?IT;C>+k83_hg@~J(-D(!wuspt|PIu_Wf8XXL>l-Oo z+G{1P6%+dZuzT?T!tN5EQ1?HKjEF!kZ@65aosn?`KnTzl^{G99fK`0^s30~3E@y7s z4aFBREfu3LrsX!D0m~=hp#}PGXJ7%JBZ82)AYR1O7P^L4N*Y1_6G_y~D!_r>YnO0ve)71>T6P zxZrMUk8{99-c~QQm~I=UpPmU{??MaU0ZqXM(O)&zqOneY)&FxbqZ38lc28CBB-*S| zu4vaRCW^gv#j<(im8|Rqa9csv+8;c`#-rAhfAIHyqquS9hT7iNR1iX)%VvIE%s+ts z3xJ}k8i1jIB|-SuoLN1^PR4(F_xTHN)~JtQnb^2FUg~^nQI4={j7;!~g=&L5E&8to z8Ls@Z8q(0i}UXyvPs2JRDX7^`QkCjU3Ad|j)mV8-$ zlAi13w(EB958d6X&aGpyGXb4~6+gL`2|Fw!N=s?*z0bw8HxMTX{BwH#RDMEG@J(~( z0-fVSNV4(DfZcoQu5;$rk&a`HM1272__ zLh}I?B;ENhCsnR)ZZIsh9k?5Ceg6Jx;I70}zJ`v8Z)`?uCD~h>Om+tIL4zPM8Hq#y zilL!&fDOBPdZYo@#c<|2U4AeuRChJ7RMOt3o2SCYYW~7&{Z5umC zhDl&Dnid{C^Yaz?ComArsF=^s&wuIa^|b6tVyNYN#O$+_G2Yu7T(4Jez{WJ{X>_ll zBaecbCY>c_?j-w?8zIBtW=4Wh=^==Eqc2~%^0mh6)4)KGdJ)H(`vc=Vq?b-p?o62O zfoi^HWi+hwX!ViHmv5xxRQZ;b-Ayw7?hv55%8$H14aX{K8GAbHYup69 zuXQS0yoZ_>{>eRiVo-pYV`6Ja!;OTJmn9|Kyu5r&hq0g_?rzzL z2p^NE*(Q?QGNXuRmFI40{q~7{{^JuzsV8|+nmwM`V#R#sPAEAcKxyzl_tUkiNKf|P z64+@k<2rmpMltbjV(ji!1i#unBy8~SN($s3{XwuVt}Z3n6(;!E$62fUk1BvqFB8B- zyR7+kZ`&)_v#SOw@d+IKI17Xm@40T`_57>7t3&hsmx~rWO9$J@Q9;DI+X~>%w@`)n z>u!_@x)t_1@>A9n>gpt`{cn4F{|V_}n}@=ckZ+2MUE4fIMsnPD9hP+83})%*_(6B+ z^nGB)nkDcJ9IA60&$s+m?hWGgsAT3F(0mYiu*lF67q90yaNx9=*-5R2gKHE@o{Vd@ zxvfPGNW$$9qybfAy|F0$^r?2z3O84*k(JfRitCozjM#ipYGEV;VG2e)17yMfHaq+kx}>N%k$V>!)=4? z2qaPn)LMRT4nzM%q`HS6{l;D~u~<>@Pb$X_%4h`y$U`9mnSLilNTp=ECl#=#rGnwf z!O=N#Oe%@-V%FBh*&(&Uo^*QPybnaC;+L%i`S{WcGTPo(S%O*t02=B(h)9(`duu_Z z>&(L%T(-JY7bFxwI1rr-C#|()Z%1#}+4F86?b8aNq$czAIXyUT?BLHGWcKFq%5`cr&)~Rq8UYTt{Dg7Gkg`JGXvdBmnDxGm z7lblBQI^kzGCqgtar5!EdZ)&)l7F~ z^6(#GY7`P_$K~!^TVjB!$@s_lO`r|5b3<(KkNlKm*eyOIyZaj1d>~C#KoFWxaD?K-=8BG3i0&+a8E`fb9kt_S0G$8)|Ww z&nFuKplgevrua874-C2zQVcbBhzUdE=wS9SnC6L6MX`MN#vxPrn*z1+$N9k)dl6`z6`3FR|*c%g{shY&!(f8-j9 zdZuL@(rk>VG|@TTlJbm-bzKZD}(kJCAEH#;-Z)byK^YQ767orOIEXl`6E^?3ih zrMWV_$p=MVr;bj<6UN4LPX{6+)z<@!Dju($)YN{elHof4*)#VJTw+g4URjZWIP5+S zUhR7q4}-4{!6gWM?AW{4>G&Ez@X&ZSDBvS{LOATfgCp4G)(HXP4>v8}hhEdSG0w&5$|XJGpQo=icI|78K5KaGKe2 z7+^CUc3e9whw1E#c`n%g8jA~6nmRg*!#XKnJ3Do1znm!S$Q1S_J;{aZAL{Z)CQL>x z3VnQh7aJKf-O3QJfigmG-W0?Erqf7&_wL@0PYqxC(GYZjSly=1zrK!LZBr|5X+94D zpug-s4SC=JC zm>x6W{i07>UtEN*v%3%uY~}iNzq`qw<}#0JYp`sq(E0^S%NQdqby-70K$l~JR_0uH z+=hC;5OrCT3EGbK^7D1Y0u||gXY1ibcJwgNQmUZl0v)r z6E_$$69|Q)1@#BllS+DRx+7W-9EgQb(4=>F-BQ4pF9Xa#|Bmeo?$aenRQ6}l(KV)4 z{vohpmrT1g0hY@&(fW!<4qX)-gb3ksu6hfbkRYH&Nq4(2E} z-*?l8HdkOQIa~dN_}`|chHgBZY7PYlpDCMV)mCak=p{ivg*!&-WvyM}-RnFo`5rY^ zk$|+5dP}r$N-Jqy7g~NgGq>A)33Rgz9=}#W?rxg{^5qDBA=-6hRX)Ji*Ehe{@t^c` zX%wd>BDCR*jy-z}XAF4z`}Yl%%&s z#3TBrT;Qu$fm)e6z&rms*r|6@^SR#J-1dxqnp#kh&eZ(8n6U6tF@6L>USP|C3ltGz zRMP1-PD*bW9Tjz&v)r;qRe7ifX`a>)Yi?h~QiXMA2FzvF#u)xF-@YBgt`m%I%DAfB z1b;_Ihg&=b;sIa9+HIkyemY9pj~-w!dHsuUkFx|sv~GIe{JZ8f8Y&OQUzyu&bMN-^ z`FSh^V08cQXiG{h z6UuUrBO{ewzy3>aFQ&|oaeaMoWcd2WI$Jur-MO$A%)GjG;tDq2X1!_vV!WE(f5OUK z%~qtZGRQ7@y^b45#+;6~_w(^t&_p$0?*bAHY;M_#zM0Fp0sc20LShjJX8|HF#Y0j? zrq)Jo-=RZi07l{nuCynFbmtRwf(IGX^AnN;Eg_6AAj7xgn+56AC80z-E(?+R&L0crgI)1|Cmp_n70?U}ReIC&_C6Gbl&($Kk>7d%y5+j6eO)-xDS*>=qB1CF8(z{_x?0ZT{5< zQ)52lMLoE;g&i_u;W8FfNrXdDU#Y*CP-$7S<6^JJ@MRfhLf}NXRic9-EoCa4%ow6kkC4 z-InkCL0mX49>Za1Xb8bc1O~Hxq=7rR2BvUt^&Gw`<95r?U+mi3{$ zg}NE?C)CbZIPN}voW;2T%dR9+1?*>VNrBN*V^g~IQJi5mD0qnc?&Ie_eeT@Xmx68S zI3q(1{TpYb#NNhwc&%PfD0r5{ZwSqR?cY#$7OgJ(OU3Sz?{Qq&`p3_Hn0#v8IBt71 zVB(H^m6OSt+Iv+muScMO@GwT@LwnKt%3gNexu0aaBI~??N`vvp0%>Py=|h9dL)PMd z-U;_`{5&%cuZwp$$?@=4KVL4gP23ZvotiqgL@ZtM!l7yHHwstVarTL{s!pLP#|v{V zvn9{oekeN_@N++npOBNwBQz@Hta1F>V814b^M5?wuJb^7LfkdUEl;(LYL{vK9kS&x z+wrdy5*9AGqNOFxwC5_x^HHkm2cGI^Q%HtZ!zpwMx0mmqi@a$*;=gA=@~{7Ua}}wo zj`%(BG8G^R@FP*l5WzKz=g|T7!`oY3AByh}jm#N1Ix0X-SWd9ezLgXeJ%WO?ifQTl zxVg^)ssU&j6r$(k;`)fAdJYX=cl%Is&1sbT?{D9~Lzz%EV5Whe0>ut?atyz|&{%ve z8)D=yfa8pSnt~MC>zD|dAF<^Vc#-cTTemed9Q@v;)bZ_GL^WfHptr=TU;P~y=Xpxi4~j1xIdv*TIPB6+Hq02E}J%e9}M z|1%hg<7)U}k@UQ4PP6?bd|)&+uDl`agf8>|-42VzLf+P;OJ*&=hWJIMB;#}f0crvi z{`TD&um*%OThDu6{S!Lr*!KZdi?y{KIdCAZgXzimabvMKP3^}~3HcA6KmRj+MbF2% zuuPtTkmA|}{Hx7iIjxrQvjd~dA10|cDOMX4g>40`FdsllP$cPP?i~ic%iQgLz(QScYk^Ona;4jjj>X?w>fvSb z4?slK**wQN7xgK-Eu%~p zdLp5#kGWq)2fu~Mc!Em)7Ar5SpVgIMN&I|@qERtMObUuzz(B7pSVS+BJjNg-R-Tp& z&xXwVm-9`IOo|$O1THSvb)mmS^3K{^q7V@LMte*wI}!Sk!+P!L+OaZ_rOYw^_>`Tj zG~h)T)q>zXfcAq&2TZ}Ze-c_IDw;JsU33NtiSbj#)1`Jjr2_5hqfRyQLBkE#KDbYy z5g38?apRF0z=;;GDEvDTI-M#34KzOau9R+wp zf=Is(kO^aB?`K5>!&LMl`5;{5;kjIDVd`wP1K_BIDkAnA6vMQox=kefmPen%|09hk zVYeOTUI8`?9*d!y+a{~u>&eYV6$IqU5$Zy^6xUeYcav2=|xYjAP4=(JlUmpQVqx_YmDOD_-V&YG!} zck}x@<`*v_jyCOxAc}~5wA=b+H#y>#%>T;YcxD0AM+9(gULNDdlII(H92Yj+BUOyQ z=o#vXi>W+7Q&;g9P4V^Mb-`VB{-~xAGbn(~jwNTyatKx1H3fX@jMg=Dx4Nth#@*!P zxib$Rt&Qd4#FcV;#0FMzRGs{5*~~rYIajF>#B@E_ce$!WsC7qiSvL?Of?iXcgr59@RjE zgfvggR>&N8#@VC*)=6mK2j`h>h4>QO1lsB_u*HE^Zrru(97)@Fau+dM<<*!(^_m~p zecH$<(KZqIpx@u?@$6pcsbx#rbVIVWv-8V%mco$lGne9|B;hda&HW{}l#7}49|&fF z<7!?~Y7!%#sP0W51t36s06!M{#ujVeu2}LgAXL}Dpx!1BkU?<6`1|<|U3-_4BcUes zSfDqNTRozpea`bs^^-3-HY(;87GbG7?fm?@Lz0btOZzSVB{?jBnB8b2CkFx8p`pCH zkG5_y`5F8Fc;+lblTr%9v-1bK37M_BrtP?(#rKwDp>r*~)P|93pQwz#m) zc4eRGxrJ=@l|O*-W1#OL3JlusT_>ZT?b}sTlq8HOD3pKMS5jgaDeE0Y0=6I6ubN(l zOsac{&FK8p++6g${n~FXzyy#xnQ_3AlKLt_jqX=(qDntl6WlAh$V59HuJa8czxzEP z`X8fHLt<9%{Wdmf>BqMw927UpDVR1?n?cm%kL_;cH5?Ak>NZD3K5PG#!*n{CjXl7> zGB?HL&d$K7j!PwNUhzyN%gV}Q>u5AYRfh4it%C5Ay^mxXvk(z^bIHnpIre6g2xgA<;a z6Tf21U|A2I|JPcKYJULmCMXTk%8Fa&9ih{jH+kf$MCZZnwj&Rq-`>pq3>=~PA0+kv z3OgFYIgVG%x##z`7zI5QkLk!J%QXI9#oy9xo32%SPB`xds*o($ZdcgRt70i2duLpu zZdvTUgt)lL`hG5E!7-RDACP@uz%|@rSm@FEB*&%SHVc(92Au8at%Ah*`YnQj8hVFP ze^3AC!J!|F@buq*4sa52|YKEi?uBqj$*E+j~1eCGX!K&9P{;zATh_eLc6%Q880* zYx!Fcv%(^_n}Jw%#pH*Zw3n|gZmwV6vM(q2rPYlR2!gDykE=w+#~9U5PVzve#lmux zpxUlId$xf_@4m!KG%4(Tm4n?;^LFR(nc3^*z=a2vD3=p)-n}A$Vz218PtIsZL3XzL z(fC5)fdqTS#5vF1y1&o5#*_a#>|uGmL!eI|{op&J4{^YxQ}=hIc6pHHzoeg6Cj*5Ru9kZS+m?#oa-4#gYcK`F} zd(q>^+g!s7wIH+r2tNV}H>iVdOIqpv4r-E!thEV*$XdOFHQ2_0_&@-Z)bX10!XI+L z4+f*G$5C(BUox?^_X2eLApsdc1Sj_ zl>XMX>eAAwXJbIawiv&tbxV5ADU@yhVA0<`KfrKh@@>cr`YQTuTCrBOE_@Q^rDGLtBVynB}PIv z&v*G4RKGpWno!_8lAUlM+JUl$fohj9yARq*3 zW%*aLJ`{UiG&62wM=$I#Y1C9%XF53}DM=Gbxz&a!)KM@603jpyq_Rs*S&7!?9)Y+z z;C~3un-wN=g?>Qgy?xv9bwx!ydOhBHKOdigrY6rzfk6cYMc`$DeWlLK+nBajIOM&N z&*n4I8ma6xe+){<);D~TQ`EQsW)}o}VWGG6%GK;bzi8lVv;~~yk|aP!GDogR%TL?4Gf&Z!ov20R}2Q5P6e1b1t*lg4i4%7 zI1KY~#kkuDU~n|!Fkh$9xoagq94Oa7;ek;F4(vbK*)hc{7nmf$Ocy42fG28FLr5X+I!$7 zf)feXbK2Y7dj=sQN^_`Tet`L>qyXC+Z?^B*1Cc>sWd8wv1>8<2e(Xe&EPBedva$*i zBkKwH_O1-0}Up_T|f!{SWd>OM!172$^C`UNfYFy|f(Ed>lmT%GH>Am*b7E z>V=M|tZ&`6E$^25DWER{FxJ`E_ZLKQpukd(qhdjc{XQWfpoMN4KszhRGav+_dm$nn z0;51!?CVp7fM$*3%FwPz_0Mrx9+1rOx##cZ4C8L}1=+DeSAZzt$&slh`BQN@oBY70^GCR9j}CaVy37 zAi(}!UP1u&IHz>pDf-siTL&7ow)QVz_W{mq+2(FOzrhEA>hzMxys!J1DE9!-u2rcW z62*Y;FZ}19L&f1*ni|$2p?Z*`^7!dfDfI#SI+CDO)4dd@mDLOAe+rNO!h}?bcxl_C>m4?D4^?0@i9?QVxb4|<=k|g3r#CNO z@g_x8#VEiiXVRMV^iG;YS$Au84J$B5$X)c~T5U0ujWMn(U zn=0_FFIOL~InEaL&nn_noyE`Gi4-_uIZm^wozcDb5sP;eqW6Eg` z-1`Yo%T(R@*J{FGD*mH>In3VtFF^8d-6FimJMNm!_OGr{YMdRe1=9#(>j2uN_<(r1 zY3F!YSve5mqpIrs|Mq~g``#$_39TNVy2~o%WQ$9=(ESpPh+=i=g&rno!PX* z@nVBb;^~lms#?Z3;%(0wJ6|Y!wetpJWY^v_jBT{?j(xj5FUoQ4-+zW@_~7BJt-6Or zUk`TO!BqYc=Z)gDh7Ft3gb%vRh@4%qM#)}Tj;YLJ6P zlf6X=-x{{7AQ6Giy3v?ISxo5+78CF9Q!j~s)*xw(RFjxxgRg6`Zd`DDd;J~pQS|}R z4C7d^tiN;J=1mBj45?6W`WgDN1iMZp(OT4XmB!&hFP0MYx2O9{j55Eh!YYnfd?D@@ zsSFviMnOl{r>G?f%?N2Go#J#QT&b@O#wY}DCx1jB2BWohZ{tvM*0iWT)?b)In^&3XtM2FHlWGFtOBS#!gY57s>u&9DfE2N0x9<8mlY=oO9_x*C)^_W zk^fpWH{w-HG)CD~m{8w@F?S9x^*F~U~aFpL!8-m{?fg4(WQb~9o! zt@gU$G#_fuH?>KxmR;l_Jehm(SgY57Jchekm}3E|IN7-DVBT8()uGPD8m5noOwf+g zN>br=UD>M3j|=;}S7h5Gl3a?75aRUeo|N8iQo<_h^x0jD3;3}K5fojbb8QCgwNF=g z2zpe5+RrS>@`_v_70QlP4K_sbcOWs!UU%z<#yc)oZq{4agm6q;6tWY2w85_E>p;)) zqFt*`7m8RLs)+Gk5O~Neu05OX(aEeX6?n=lP9Q*QW4-!I2nH2c+tLQ!(TCDayNX3dS;ASO7_%yWgluVKHQrSCA!YW!6qTHmz_N3 zeKwCBVIy(V3@#06_YR6el9$&h@5S4qZ*+Vf40*FA@ZRmfqo*vqfi>bA45~I4y0KgjSGM!xMFOZ_|BT zW`PJCjMdbPLsGRg;Xi_<_%t>5pI}W6XA863%U4}Wbfwu%Gp_g)J`;yv9)7!2a`Eq1 zMOkYBCUvlM!y;Np)mIU!4+RFWE}lGXFUDcZSy7kTdssMFRJgF{*K4rI>84J%t_h4or|K5VsSJo#y)pQ|5=7PrtP*>)N-%xR4uF9W< zBZLFY;!NlCqCGyOh!RlHz^o$cK%R0?E>l&U;?uSIBG$4R(cky`tNr*QnujBj&*=%X zzG)Bl&&L&p)M6KpoBw+C(|Y#CGAG!k`{xcd(AjEMpqyOaI^iAz2QdHN?)T13mdT!P zf7}=ZjoD26{IrUJv6-T!%BLT{UY=F`1?3~m!QK6NvISuui24k2{rkL^gW8%_P0ZSY zE6;z|RfIo0^wB@}V{rlIbHTtQi%$|5RbDX=Rwz z4gHc&_RLjz*$*2lP+gp*txrpc>DDU+nAR)#`)T@qpw~Z17sf7}t1oKt`AS@=5Wy~W zad_c4Nnfc-rv@;X(zythcwW=5cW>8ECN7Iar>2Yz*;Lswk0YWu^yj3!T(V>s*KcOm z-n~}@#|Y&hGM->0`d>0h+LliRg7 zzO(D7tt6}$M2tjM1*Rv|w)oaIbiPuFkcrz*BE(NnbG;7}>fdirXH120 zRPqQdrRpT11SLjDAU8G=;e1~kuBLT!w5#)x%9V8dn?>?7hz}I zbAECPZ5(6n(%xvX>>kj2mwcQyB_Se6pPNphHpsTef2tzh;^;lhNJ6c4&mhy^X0Dac zlDTy%X|mcI^y=`nm>^@)!>VZSQRWJ>W*%{Bti?Ls1xb%;ST7q%#t_%@~M&0jcBjhkX$@Gn7fg}QN6OOvC-NawjGK} zqU%}5qP0fJ+Rd%AF?@Dp7+W#lLR}-ogR*rT*NRQ;;PCkTO zHOBL};^Vdar)|5gSAwa4TXmr|-z=4#)AH~1()J(m8b#iX8|ybk->+BNpkS=mr!e@9 zu_le~u_4WRKCA|zAs4eYXB}SZ;p%P+5(E)=pQV^={BHV8YL1EbIIRYlVQC*l$c$Cm z_XLd4S`@~;WZW2!8i^N9_EsQ-S|tUMv4k06>>O2C1}Q{}S~avn-xDSjxrBKW8Jr|G zb}hAKO63V$A}-35%b#i;u{IJ3DRIKW8q{D+HKRlrx0r)Ll8bzntMDinl=Ho-H21$5 z>U=0h2-_l^j%S=CbQtRJ<1pS+nIbq!mCutJ;#wvLV@c-@YT*T1r0`?0KYb2;oWO@w z&(&U&WyJgYtvd>eZ;TTo*4!Cp^&)6~Qm^5U0e9UrS_ZLHf-r;QA|<$n9&vI=M8*{cxIGxN!PDd6Kvnx$*SFJCM@CZCuhN&D@Z6*!RS_IXokNIv zuf9k!CSYSJQptFxU zD1zFk=0&b_u#Xwj=`BLx-d%jcZAmSSh41=_5#F7uKS=!G_L#8U($4#M-MT>@-%9Ge7-XO=w-L$My|1g3zmUhT?dI$toD4Rg;7}^ z33Mg$J)CrjmVfVEiTI3gOsQwldLNo$?o&z(wHlDaaxqN0Xnvj}*Op1`C}Hb})gS#L z^W{iFCt42I-Qko;G{1C2PB`~W4-&JskgIJ`rr^^XgpV>#D1a){zW~zZxBl zm}O@KfK0W)v(yUWE3c{SL`zRv6{de4MPaJ9U6Y;I`=f#B@nwFG#o+LzS9Aci> zf&13?OLNN$Q z0?z3b&idh9U9bT&)}N~n5!J6Qwwim-%5$(+Aqma<;|^~terC_IaFTw>@x`Xd@nNhI z_9TG@CwrrzH>cWF8lPN|T{c)7>`$GIDU5VA-F?=*nlz6=uG7YguX zC5BH5jkc7Vl#xTpb0aB|w2I4X*lB!X*6_wXWTvuGHp47Ox`Y>nzE@!P<%wql*?P^Q zUeAiRV@Ah+w(jJrMNGTD8bQxm0Ji^lEq2CKNmbB>thUJ9@x*TiO#O{Oga|S^F+nJ4 z20atMpA?Q4j1ry8MXv`}_Tj-5V5=@FZ=JI~K*|8pCrX-7C}i#b?Rw+(u zv?u<4?eSkc2kj${ji@gOX%6^O-5M1#p+SN@T8&UgzQ%f?T!p_WYrq>roC6=ly`x}!?{=MwR}t`q7b6Z4f41Y?(X z*p=6-+G?ObJ12zcokAhr9WP@7R=-tlBBU|ohoL{}G%yqc)$Pozm=khpV!a51-oR^b zyshRSy~u5gze}q{A0Um|a!eqFTt}|em-P!fSF7eKuYRFmgy{5<8RSMXrW@rXc!%18 z79mIzo6kCy3~+&Qqm=|YjTEWrKg1ocI*+GbtT(TgBqYacZe*i*Nbe)HDi?Cpvb^c} zW4O#oCA12NCP9|qZ><(01>>2{9F{?ljXZakUhgG`S*vFJRc}q{=a5Bd)w9#R>+7lo zNcAEVit2o@_ZXirj@C(WYhn(fW}Q_K7PgsGs8lHCoN!BoUYTex7*$@bjOMo(^m?6c zCEN-%n`+B3dopIzi@I8>G*=R za4%Cl`cI_QeGQ}rPG)sLUU#D&ozmd75i5!vjrCEUf8QtqIyh89&}km2dI+80zPP5n zs=m$}G~r?qxt7AHz`@ancY;(+9sG*QYfz9lhPpd5NM`KeQm{ zEGYPiolY_0;BcMRuOE{8m?$-yPXDVubUsAc?{58aCP%vluj|x}io5NDhg_-LT56=* zg4->EtdN8uO~E|#bR&D=`EuFZfz>aZg^Wa>7AK1ReF|km9*eqva%9WxXi*La;u`)d zV~RUhySh8{LwBg?;)3;YIfJ4gA^M|p(V|vMZ@42ga)<5XMRhfYsU7)J!s^E;zWxUK z7DyC*&Fd0$CnC{p6Cb@qIz@D^SzjfWJ}_j3l5`PSw?Rs!memX-Js9NYQ&(k@A$W= z5-Z7tFS%>rY}lZG39ZFrLj#K!e{%s2FHfXd&Qy|FABBH5=98ELivRY)iv0?}g$fK{nc_7jy&hvc|9TqB&M>NfW#%Gfu+{Y0 zzwV4>I~O#$lJFBQcyH0v!1A`3ZWrB|2x6xO%hC<6$k8Ehq;;oWF?|Y_Q$`yckQIRY zL;|aRx_c8Z%fxc~E=%DGrkaoc`V4&7v?|3VsQn>4B+q3%Q4oG2^xdiIL9qNt;T8!W zaxhNx(**iwo6N?+(Q{j(&8_k??<$!UVfihSNsG~rtJP8|Uj=q69zTRY{E*g-NTEG# zf7m#Y)d`bQgSyBp3vII_S~OUyMZ8#QXmUhPI5-}8k4MPYOH&bZE|RX_+PDjmm-w`| zYW7d4o4~eLBpBCGi+MI@{#lMcK~$ISx>FAp$|H{Dlkbw_D85$LzB*>@!&8EHm*2Me zHMrLS&-N@f2QdG(qR0A-X|&@q$H*}AldRh&0*~suIcev=Irk!s^r^%$e7hcb6Jqw! zusog*?|Jf@f`FgmO`88aj4SavOHiH~^VS{l_Zbn@ebcQs67EvLRlUmBO~^-TsAS;M zLxd1DfMRX%%C-p42lN(skMuih=X$vkZgpA=gSWH6?^<9i^Gu9jc()n7oIz zvshyCtC_Cbfki#xXocWMD5RkGy?yw_07HF!#AZZZRS3G2B#mFyR9hH2ymy^;?%U1T z1mn$Ha^;IIm}6bxVZ$KlY_;ZUnwZix%YVch|=uF~ZQoslY}ySW;v zxA4;KQ|p3&?@1yn2A9R+3CN8$`w=~B_kHkbe&ad4PLC{$!s&pSam(#6KqHn}I+=A- zc_dM^W9Ds?78fmxTf#6oOg6xvo}2cSvbNwSQ{Sku_OWzr)S(s@S^9*(r(dmrDWQm6 zgVV)-W*Le_=_jfAoLH~2`lm|4w`w@L@(c?f5n^fNQw~|a)}m1`_up_miH@-NL#jEA ze7MEi8zdb+QUX$$a{}pgD%o$^!=hq<{h&4iQ7#@DWAFS)y2LtIl~}!B)@OOlyVq3k zQ$nXbKzr`4_wMauqoJ18t0v!8rJhd7U_DKO`LsZ>%gWAW5fUzi7}0QrZ5*!r3woUj zz7B_Ik5K*%-MBDQ?C|-4Qj*0$rH}l!pdd3$YnL{3DY z+1Qb)jWQX7PK+qyY`B5}*}hyf+)9?65&I}$6Dss-D>)AjZgkBwYa@RFfcW#4l^=G( zL-GGaiBjk`&psXI)$G%Yd>GLC=U3C+D?32OJ8B=_VzPVYt;7B((I`zAS?BP#ieMZ3 zHcBN7yPQ?}KQLR4Yaz7qm^CbGwA42RWIXqZ)4MCZcHYAi4j$2=d__$2KvgWTy6C5pmF`*m4u z8}z2J*=&L)C*v+urg{un!ml>wtS0`a_Ei5V+fx56^UC*uoOz9x@1kK?v*8JNgE$Lg zmvz-=Cs6Qd1J-f9cAN7HCk~!k9K6a8Gv&<5?1JYo#kc(#g@g~e)Uh6d8!7eka zBzg4&e1^tSLmtg(;-30{LepQ`RN<>N)2x1&+jqq%J5h7*np*eYD9&JBeiiy2#rED$ z-fYS8w%Ha4Iw9Pc1FUH~aRlVzR{>lHyk+-)3`BiBeT#|O5aAFb5)ZR5ANUPkKjTz# zsrexX%_@pBEa0uguj?=WS#TbqG2u-<*2qk1Zt_6$S~z3)|KcF#qUCX?9q38SnA`F^ z7{+14mo+0`-{Ex}hV)aN=WSsMn;OMM8JL5wmaJY{ncXBDt5(cZR@A+}6B-Yl#uq-%5L4mb0r|f6M zz0YrzD0bd}o?0b%+xHd-`{K%&V_+?d)XU(wfd%&kA80jkbns?UJAAi?i!~P9pIoU| z8*X0k`Iu#~@o~$3=>LT=uV+~v{;@=@1}c0|j@5Y^N$C?ix>ou!JSq8(cc6cPPRA)1 zVop}Fw|3%%naE3zHM2p))|TYQ1seyU9bE&W=oxQ#Ymj9aWz{PhEM?hd)%n3~b+LG` z8*J9*^V?QmI^`MI!q9&X_o4}9?u3}`35}zF8zkrUA=T6@S_7etoll8^_le>ny=!H$ zPw)kO0`T4)*6vch)pyy5eBnsZ%b{Z>d^lMHa(C`bcW%21%vRtEe67waYO&&LB~jVw zAhBdt>;d$3;`evv*gHQmI6-Y!(GI`%dA=c zajmQVaz5T+l}9zjAXzV3v;cFdl-L|A*>Xr6#7p*Yg$}eN6@fSWbO3kV&S%xEu>y7~ zg8AjsI@0dF16xgF4>_o&W#|?v7>F2jmb#8S4P2VYss)$IhZo#&H$5 z-0`v#M}YdBnw66RL#+?y1f6M7>Ft{42NUvzKxhcH zB_1};z*`rn;KQ4%6jHdq!j`|yy6vdPeCGMZW4Mu_A>cm9Sd`{1Qekk^yK8O7{n>)A zGN?@L63W_*D?i?F8rID;9<#dH6=2T+3NIB;1m-d(Jq6|a+7Ft%;BsmZG&3my)LPR$j3j1Br)TduE^3lcR+q(Cp zd%>sz4Ol~5>HE<1(yUFXNFW(3hjkh%Nh9Etu&^MI6pPQoDR_6%zeG7;-D8PLJJ;#I z^IfZ7^9RosWtiWZS*8pNjGbQJ(yqp78H11PuDgBhMak8wT$tdlOw*D4MnUsY9axE# z0ozD*F4J7Aa8xz&Qc><;bY<^uBC@NP0!26wuQFM}(C&)T(eHK+I6}VrL>p{&*Wr&_ z4}t^8T2B~o*!9E$7I)(P_CRq0at1WohH(eFRKYBpC2Oeb&WmcrbZU?Fr^7mFkq>}d-{F4urT|| zONhb>FM5S9R$L&f8Yu4k<44hZt7fmuWYr%xbdgv=OLd4W`0TE7Phu0K339{Ku%%!Ta>wpeNzaB zISPLmz|lC2ZI-j(;%IWMI7WUv*=J?TYXc+d746NEzX~%ie{HEKwRQQv)8fdJ;5Rob z=N7)$$i17BZ7JwLk-SMSDqC+-|5ALerdXNtoj5#v-J;y%sPjN6hZ&b^x24x7xQ_1R zvOVm(l{!vCH4Z~HSB+><0-U)(z2>skeM%nrtazW6h(k1J?Q`^O8ZN zr`-qe&EoN6tz0`-r4Jzv9EOQD0cSc?k7&fS6Rw78S*e%ro6qdO@RSxEEN8a7dnmEKegYt%9&j{s|-v%3=RS!>>^$vrxt zG>~Fa<-#+ccw4CVHd>hH>dx(ZBdx1Z>deP0x!}Su5Z?*!clNtJ;5)O6@FhXsNP}t5 z^jl*6RY30Wz+&k`*qbOoLm@AuXdINdkn}Dm&C4T;p8!%d`d!9HCBgZ-Mn$>aIo_7; zd9u~nd0qFDE4~M)|cU_wltIQ{5wevO-1Ez zpGf2!jqQK8{y0-(wK*hs&m6Zy$+0vB0+He5d-=7~#Z0W_{jFuqwtIA@&p2~VL_aT0 z%W=vtw|bH03JTzx5P38OW&EVd*my3HXXI}&ADs!+0#V|L9N2)jZ4VA(>EHZd8%>tK z7%+<#EqYLp=H4}TUg>j0yUu}!PoB^S>faR9cdm^!Qfc&#{TAsXaQ|4y=$$z|1oj=1{Em*ur>(J{w*NL0#t;Q4M`?}bu zPxThLA|s#7ilge+^DNDbD*D`$yFm)Yone{BJDuw8FCRMA)RpwU-2V6hCEj|;ZG+;E z{OX8}{kJHh7Fv1EJubMVHEdll_QvhpjA?7*vDyxH3uUYRoIBNOdZwn*`HQ#n+ow2# zGqVOtrZNH%hzjS}*l&HygZx&R>PCB~4R&lYkq$S%ACnFnI zUSn=m2aT!Cb1xnS86X)K$(_qL+Ho24&_C)g*C4jG#&OZxcx(B4+V@j?^TKm7w{L`h zL^&KXJ97AH&KuLDug9J;v`2KsBe^qI!oz9a2Xi|9vAQ*xN3g#Tapq~N#<5Svm0A>U zlAw-6sQq+*>~~}8-Igs!z|-h59nQS$t(f(`Ek5PNb+aBZ;~B{mNw(FecnO_b1)1~5 zv-(WE82^YrSK7H-e2i2~wM`68$s|~eO!P8)wFKt&V%kdkl4jDKluD?Uq zGtdph(A8tJT5-2h7p#sSey+J+_Z08AUc7 zR=HGG=aYn%E%%bgTGlVfu=}fhe*RqFk#9P2`&_K}iBPA|l-~N%83p6{yW8nS`5R4k z2n3gsnK8A85IcUSojr5uIH~-BHE{}UnU^{K zT}cgpMa5+)K+#OgrQn9O`*Ky*xPQN^0-W9V)5Fiie3*Nl1y1(dwbkp=UiP?Q*^?_X zs)$8m%N?UdqxKZ!?>uDu8v7<=C#o)LZzlO*BPU1HKV8?W-45S#+<0;f)rD*sMfrpk zHJU%Ag`^p5lDXW_u|)(?BWyyID*9a5_u;Eq|7q(%QgPRMGnG@1U~;94FL&B>P^avU zHKpfWKwLFvSfu@W`;QfOp5|sJF3Imq3yS3%=W!WyEyVR2CT93`ii>2P@iSO`x3m3V zwd|@=#zObLg}ddZGJH?Ag?3T2yX|8*AB>IpN)kH?Lae)#(*=Z7O*vO2&2KGZivi}a zDZfu6Y0gmfcaTpm8{e-qD8jx89`g#tms}0;>f=eB^YMl7vkLs*bHu0l{K2ZW&7oHARx!so072ft} zI>g`hdUeRHz@V6bBE7i_J17Sui`1<&OncLAZH+CbPu%**4z8sgN=DK+Sp%1l&G^x1 zex*9I-!OunYmx6#>1%!eolE6;uT!qr+dpiqJM)X3uFQcIb#)JG|2oAPSGl+@cTu0( z_etrRbBAT-Y{VO^aOmEAGE#Jqe#3u%c8|^r@zkBD23Ai}so%qkc=#Rp79}H7oyM?D z?QebdyAqJH@=qCYZ}}KyTM<1;;k4tL6xVy_dvfxfTF9}D_7>kf3I117GOvY{4CD-G zNG8da=-zO%7-P@BlT~2bK6|GnTFSxWe;c?45Ph_X0kva9q;%`r1 zdmkAr=5lx5$YR>l+qp9G<{L{m`$Lw-*1ETlF{?6rGY8UmzTaIpOQZQy9t7*%q26(K zPWE)ScCi8;mVBCenlw+%9Y30dUVYou_qqOA&b+uL&pqATIRdD^ja%sAQTki{aPQSb zYTeh{t`sgtEc)&|yXvTG1zlkGE*=elr)*k+_h3fDSPo@&&vG= ztFU%9+$?qNXCL(y_hHN@vn^bx-G22`M6CEmM%-uVVp%rE^d{68wm_=oQCL)%F^TWO zMl8`>DQ-k4Z{bMS7Mgg@dk3TLoSZp@!R^mBAuie{)MnngGM~BYaND)_E+0}Ft~OxT zi(_b4wywcm4nbFV4A?D3diGrzzw7RNsP+`>;4zjf@xxi5i)x4cAMJg4Je1x0|5P57 z^n_4RTJ?mXc$&!)ZR%5&o|Z8*G)l6JL0KYZXdx0RSu#nH34>A0*k^c3k}WZov5b;^ znZ`1fG5VhS*6;WF{`39s``_33>%Qkc_c_|b5}hbCJ{xNR(+aLsoI6; zVp1GNa^V57=^TgkeXh4xPL6Z?{X$|jSxR;Vi+a6a^*lzLrO=AXC%E!HT-^bj+%~5Q zvm9U2$KHBtWuX0Is&hL9dhT6c3tbYGyaF7EAXDq@8nREUn0jGzmR`q=(lHTkHyoVE zS=!N@yZ)@xpfAto2z!F8--88zIGif7lKiC+H>x4I?mk%k2GnW%wAh-Nt-p?k2;$U- zxc3$wRDG`6WBm0&HOnTx$L`~g=dNVnn|S;ACC8kERvf1dy}_ihl+YAg_nFzGmz_Bq zshUzl>UVB2Dp+nQU-4)AZj+@%8ska>c(QURAFlJ(a0u4 z;~c?*p#2N}G3^>Nrd@(>Lk}99S|-_V`eLwL0dZ$dzYvv zei-)|Ic>+_HT(KGf4BV`k5nO8Y9~RzC%&VH zm$Kr>ieo@a&TC&PEu1pOK(0fkRfpqE3KwI=*F-iL8W~RNvO@wM7QaaMycx(B9KNi( z`P^H1{PkL!aTLInA!Xbo}2n`Ms^BR-fk-xXVDw*LAbhk|Jj3152 zDE{2*kii@lPMgiOU<+SJcf@K46(ce8G-;tMpQG+}FoGxpv1N2KWN(AR5^RGDY`P{& zEku}#qHksQW859Kv;MOqqT11a&v?v_rhxZ?X5{MUd?$tN?98_q$(eWm9=~$z3w_ur zi}IR~mwz3%2IL32y>XN*j+5J=B13mf>qXA%ubZ}5JZr%@Q0eGbGq5KIS(c}Ie^FyG zfm%tT37vkC{2)()wIZC(sgjq~`q)CJ0mt!}oG5JnKo+c17)WK&1^etv9Pddaet5+bg%SDnUPQq7JwFw7-Z+m9g8yR6wp{GaBWuO)IZ+Y4Ppm4wWd z{nDX~B5LMQd=rDHIc*^;fwCHjXiON6A5LQ7v3+zu zH#>|dZqulOJlF!Fh>EeIC9jQj3$0o=ZUCthX}I8_y;1c$bljZMspC7uxpu6^rWYK$Q?Zd2MG>vsM@x6}?3jFYm|o zOVk>fK|&JbecKVjvQ+Dj6Q!}Ft1(sgr^T6E<@k;*F9;>aJ&KZhpXKj08&X%S%H+xh zxLM~E1d;@{;)5pxVq38V*)77G&ho%?njj}stuJ*mJ*k*q7O$8tHGHeBDxvclao>=v zKfQOhVJG!!PhScIeB6dOb^OSMiaaC0Qg1lVJ1KV*8{>m)Pzh0L()h-~un6am&@&V5 z{j0mqmgsBD$p*Y2`gaQlqWSyGMD2cM0C!o^r2R2S$C6I~fX;LCJ#ZOx*U_erx2h$1q&MHpA~9H* z4l&y+`Xqp>5MiwY!^}MlyB7r+T}A`_GQ*4#_l36WgSjrxI=_7__nArZ4YaQFxR^j6 z&vQN}Zja+PwV9gNhFOlO0f!}lZ24Tcw!lx3<)5=jeAz>Jr+&9BQiBJmb58!w>#?*FQ0YN#MNc> z_rD~7_%u(SXV&k&i4gz>X8B0ISIX{;k7W|)?M|fAbCO-E)Z@fN{eFQVT1rH1zsfOw z1+8K6a8%CxEMtTF@xLV(`fZp6rBB@{eO^`3$gLBEVrrnaiifxNK)M?)ZERPk?j3)1 z;6G*ZG%{y6f6Q?^^Msvij*%*RF)P?MImx@*2K+(tguUJq^Eu#Qe0j`D@Zc-6!DZ}0 zO;6M*jg{BW&u1B2x|v1nsP3J;N3@vKqkiZ67@n|Vyx=SW-YZ_JG|@KiW1WTXgMB+-5-O$T|LPl zp0uDcoz)LZBXU(EB(u3jvBU0maVVcYgV~d0GT@vlxkO=5T)?Fz7 zm!tSgeNV;3U!~{!8{*~yCX3e~4#zr%7E^_s6a&0?uKFLI z#=ij;1I6n{^Hg=fBB%q?I~q#@D&`fa-`XrCzBqlT_xVLE{z!>|HrN9;a&kGfy&A^D z_12E`&WfxfrH=TWkon2I1iL)C+xvs@oay&gHESp8I(R?k+BN4nOgm3j9ZdrSN|o06 zF{A|ywnxcfeAAr&Q4(>Uwssnmv>r+pw1&?VslP1#ScLVph4BAXilwP1o9A zfn9*3ln9kQ(hHHM2%7{=EyEtPSrCz{E&nsZd0l7SEqC45=#IG?lwn`s5a=gRaec4t z;#Z{rXO~+>gP+-8W|!Z!KPMS31)t`a16FdQ9Y9Gc0I0H0hLr^8fL%pynooZ7fR{Bu z;a(`9xf&V|p@{PCU6&1G0FV$}77nm{gMPmIB(_o<)=XB07}bV^d2QAHL%vK#YC&Uu zBN=SY@Lh9`_hz};ML2W?N<5>BoAqD?fQd1SQy5QNTx$~H6SAnZdOETmyEsT&Ekshl zfu*G*SGgf^n|@Ll^pKV0$7-3wskW6mSKdCtQ${G@Y`c4o>*B%nmd&Y18Fp0%Q-4_1mAQSu<;ToT$h~&A5260;7vjP2AWHri;ngyh{r< zt>MFVMEQ-ZfjMMQj%}BoEmm_bwxKn2e%R9eR3%^wB5H{(E-@St_mUnE1UH4VY7;o& zjgpb9=2mL7sR*xbwzv{eJ1|?6ExMiSXylMn@&sR0H~Nazt3X>L%-}-8xEW#)Vt-J% zPKurVcwwFEQF30ClXvtct|fuT1g+RA#)JXWNmOj`qS+?;Djy|9*n$_!yhtwE^Y+ve zbDP!vqB|tJUk$(;P+klVWBf2S=mV!i=1 zM7Ie2qU2IC>`KbZ$F%@BhRELofs}vVeGcaNm4s@LtEV)`?^!#p(TmY$U+7~8@`Ttl zneB&x-K;WL3I3MGp|LMeg*JWQ0IW)FdtnABw#WfFP5&OxVW=1$lAEBpc6k3{j@7h2 zjC8Cv+euGEfa$p9hC{d|)l9Z9@Yr;Kv}y{$W-PcJroGwPr`)5IcubL7=mev^of-3!5}vtcpL&p%1zE-%97tzJ_F~d>qccV{%JZlwxK~2w)Ok0Y)}I z!oRBSoUUskH;xp41;SL0g0oB#t~?ILe{icP z?$sd60j^=hXv`$7gz93BvD%U@0hZc}9Qm^Bm87Q4N|rgP7kMeIV1?Lc0_ke7(ly!P zx_~jijv+92;`nH-a~!(s^QQEFr4WbXvvgmh2tKUv5h_Y)7}6;8(!ArQLF^#Fv{o&Q z;*rrE`UtO@Y`J3-K^Hk%;EZ9T`jggfSR;XWc}n@H)8vH#N@31yA)dejrhiPi%>9zx zED7}Q4aYvqRh4WqZ^n%bYmOd}5+~A=oDEtW94j9mxIbnN{McW1TQt1U!we7tDpuZR zS=d3cHvzNU@NyDI^kC*;!l7B_^AYNW$%ur#gIHJNMgkEduP6kxZYSO)(pFDJqC4aN zN#3^|=-wgNIyt%R=qdO_QZ8~IoSomRa79K!{BgW%UmWV*iWLa!H>P(T@{G&sl?M&o zO9%b_fY668d|)Z}Jad1K^8TQ~?D_e*J7nU=MsH?a{&Q${BCJg}x;@@gA1Edo zHD1pe;+jfBn?rM0Ku4bwWoBjRk=9l~O-`1i1w@D+S~l!^;cp_K?meVH27=6pLI*pB z%(;qi-bMr#xnmqGiMd1=6({9ag9-k=z06;fzHR`yUKnvTW$v9xtB*L&Tn!wA{K#y% zlCyS#c(ArL&6p|Z1|)Z!fa4Q3lr^)+k?sgd@n=%=42QglS2}&Q$7B8wiXN~N9Ed$n zm8`wCZbDWk@!M9tL05c-w+E03;x0(3M)NJC7Iwrbc;ig*rV)~h>Ht%b>-9^uLqPzv z?RnAr%Y9X!L)7$WcLHnv%o#hKPM4VhueF_kWu(62YPpBsudqI;$+$T^jLv{zqwAtd zt$uU(qn;hLyCJG|)hf{w*6hSSpAoGRzV^N0;(e08dxwsypS?jjz5ejo1tEJda95`N z$y+G-FvIuyGQpubne$+s^IYvDMK0JB=g9ucgFn($BCO*FjH)h_QIZiW5kIpA9W)Ehp9Nl4QP;Pcr}4s8-x3G9!Utzl-fmh%%w~Pn0xj=U0B&YP{8Ut`ThMSl{@-av9a!B?z5ojfY8cq z2t+4#!AiRx?A<&Mz|SL3-{x6}=|GUn@zb6;#*lr(gh9&l;-9q(Eg!&xFZ<7Fp}zu5 zh{%IEV3e_SHalDl$RM4N{c$2m1q{myZcO>%hS}`wc;B7%U`Pj2?_W=C02ljqLL4cN zI3c^>zQ6%LFe!UODML1(!D~ApM^IbE;B6katg>6H0mxB9fhfxk zhtV*32!vzyt%E5!avY56a7a2J#oh=e{O+NPDdCG?V#>k+20-+0hdMr3eQQX43S7L{ z4V}nIh=BxaTe%zy48|(O7}PF;`#H+e9)S2%9+?0t^jw7J=JFL_=L@y>LnCLv)g-^q zUIMKoL)`{D%0aTU_7rq>eNt{3T<5AoeQr$n1Rj6f0~zg}tuVC`Os!QR!C=CSDz*aJ z=vnl;fD}= zewQmS50-A$?}P@nRDw6cG%ekHfW>U-dK)bAziTabfmmh~(9mUxLM-bA$N*h7Ac$p4 zi$E-|7YM}i!V26T%Lrr{9xTHH2rMtdgJpOC$-y!_ScV6X94y0w|800cQMuBLK&-qB zl^>C eEWhwSa%rXCmYG=pqhT Date: Thu, 5 Dec 2024 18:35:20 +0100 Subject: [PATCH 02/36] chore: update captcha not enabled error message (#1774) --- docs/errors/sign-up.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/errors/sign-up.mdx b/docs/errors/sign-up.mdx index 3c1fa0b59f..9a8b20c28a 100644 --- a/docs/errors/sign-up.mdx +++ b/docs/errors/sign-up.mdx @@ -41,7 +41,7 @@ An index of Clerk errors related to sign-up. ```json { "shortMessage": "CAPTCHA not enabled", - "longMessage": "Bot detection can be applied only for production instances which have enabled CAPTCHA.", + "longMessage": "Bot detection can be applied only for instances which have enabled CAPTCHA.", "code": "captcha_not_enabled" } ``` From 2ffb7245b0240e3e96ea77afffd8826b503bf99d Mon Sep 17 00:00:00 2001 From: Brian Morrison II Date: Thu, 5 Dec 2024 12:38:38 -0500 Subject: [PATCH 03/36] Fix reference in user metadata page (#1775) --- docs/users/metadata.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/users/metadata.mdx b/docs/users/metadata.mdx index ae75fd30b8..a7fc5cba2b 100644 --- a/docs/users/metadata.mdx +++ b/docs/users/metadata.mdx @@ -198,7 +198,7 @@ Public metadata is accessible by both the frontend and the backend, but can only const client = await clerkClient() await client.users.updateUserMetadata(userId, { - privateMetadata: { + publicMetadata: { stripeId: stripeId, }, }) From ab7bb82d249c3a9d91587debd11fc0d45b99f836 Mon Sep 17 00:00:00 2001 From: Brandon Romano Date: Thu, 5 Dec 2024 12:37:54 -0800 Subject: [PATCH 04/36] Adds a reference to the cookie overflow warning in the dashboard (#1776) Co-authored-by: victoria --- docs/backend-requests/resources/session-tokens.mdx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/backend-requests/resources/session-tokens.mdx b/docs/backend-requests/resources/session-tokens.mdx index 468659a991..ae43ef8737 100644 --- a/docs/backend-requests/resources/session-tokens.mdx +++ b/docs/backend-requests/resources/session-tokens.mdx @@ -50,6 +50,9 @@ Claims to monitor for size limits: If you include any of these claims in your token, use caution to ensure the stored data doesn't exceed the size limit. +> [!NOTE] +> If your application encounters this issue, the Clerk Dashboard will display a warning: **"Some users are exceeding cookie size limits"**. To resolve this, update your [custom session token](/docs/backend-requests/making/custom-session-token) or the [JWT template](/docs/backend-requests/making/jwt-templates) that is referenced in the warning. + ## Validate session tokens If you're using the middleware provided by our Clerk SDKs, this is all handled automatically in every request. If you're not using the middleware, you can still use the respective helpers provided by the SDKs to validate the tokens. From 1ec16e1507f71e3c82baf8c6ddc82dade86c867e Mon Sep 17 00:00:00 2001 From: Jacob M-G Evans <27247160+JacobMGEvans@users.noreply.github.com> Date: Fri, 6 Dec 2024 07:59:32 -0800 Subject: [PATCH 05/36] Quick Typo Fix (#1778) --- docs/references/chrome-extension/sync-host.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/references/chrome-extension/sync-host.mdx b/docs/references/chrome-extension/sync-host.mdx index 1966812b66..f00e995923 100644 --- a/docs/references/chrome-extension/sync-host.mdx +++ b/docs/references/chrome-extension/sync-host.mdx @@ -116,7 +116,7 @@ Clerk allows you to sync the authentication state from your web app to your Chro > If you have not [configured a consistent key](/docs/references/chrome-extension/configure-consistent-crx-id), you will have to repeat this step every time your extension's ID changes. 1. In the Clerk Dashboard, navigate to the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page. - 1. Copy your Secret Key. It should start with `pk_test_` or `pk_live_` for your development and production instances, respectively. + 1. Copy your Secret Key. It should start with `sk_test_` or `sk_live_` for your development and production instances, respectively. 1. In your terminal, paste the following command. Replace `YOUR_SECRET_KEY` with your Clerk Secret Key and the `` with your extension's ID. The final result should resemble the following: From e64a9f85e8c5c8bca0601dc4464a1f03e53eaba0 Mon Sep 17 00:00:00 2001 From: Haris Chaniotakis Date: Fri, 6 Dec 2024 23:13:48 +0200 Subject: [PATCH 06/36] fix: JWT Template shortcodes for verified email and phone number (#1779) --- docs/backend-requests/making/jwt-templates.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/backend-requests/making/jwt-templates.mdx b/docs/backend-requests/making/jwt-templates.mdx index 4dce58e567..c07b5f5b1a 100644 --- a/docs/backend-requests/making/jwt-templates.mdx +++ b/docs/backend-requests/making/jwt-templates.mdx @@ -123,7 +123,7 @@ The result of a conditional expression is that of the first operand that does no ```json { - "has_verified_contact_info": "{{user.has_verified_email || user.has_verified_phone}}", + "has_verified_contact_info": "{{user.email_verified || user.phone_number_verified}}", // fallback to a string value "full_name": "{{user.full_name || 'Awesome User'}}", From 86708f73bb21858d6d8c0f484cf6ab16222a95b0 Mon Sep 17 00:00:00 2001 From: victoria Date: Fri, 6 Dec 2024 16:56:37 -0500 Subject: [PATCH 07/36] (/components/clerk-provider) clarify how ClerkProvider can be used (#1759) Co-authored-by: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> --- docs/_partials/clerk-provider.mdx | 1 + docs/components/clerk-provider.mdx | 8 ++++---- docs/guides/authjs-migration.mdx | 4 +++- docs/guides/waitlist.mdx | 4 +++- docs/integrations/databases/convex.mdx | 8 ++++++-- docs/quickstarts/chrome-extension.mdx | 2 +- docs/quickstarts/expo.mdx | 4 +++- docs/quickstarts/nextjs.mdx | 2 +- docs/quickstarts/react.mdx | 4 +++- docs/quickstarts/tanstack-start.mdx | 2 +- 10 files changed, 26 insertions(+), 13 deletions(-) create mode 100644 docs/_partials/clerk-provider.mdx diff --git a/docs/_partials/clerk-provider.mdx b/docs/_partials/clerk-provider.mdx new file mode 100644 index 0000000000..d64638d8f5 --- /dev/null +++ b/docs/_partials/clerk-provider.mdx @@ -0,0 +1 @@ +The [``](/docs/components/clerk-provider) component provides session and user context to Clerk's hooks and components. It's recommended to wrap your entire app at the entry point with `` to make authentication globally accessible. See the [reference docs](/docs/components/clerk-provider) for other configuration options. diff --git a/docs/components/clerk-provider.mdx b/docs/components/clerk-provider.mdx index abe1e84ba0..676a3bb84e 100644 --- a/docs/components/clerk-provider.mdx +++ b/docs/components/clerk-provider.mdx @@ -1,13 +1,13 @@ --- title: '``' -description: The component wraps your React application to provide active session and user context to Clerk's hooks and other components. +description: The component provides session and user context to Clerk's hooks and components. --- -The `` component wraps your React application to provide active session and user context to Clerk's hooks and other components. +The `` component is required to integrate Clerk into your React application, providing session and user context to Clerk's hooks and components. -## Usage +The recommended approach is to wrap your entire app with `` at the entry point to make authentication globally accessible. If you only need authentication for specific routes or pieces of your application, render `` deeper in the component tree. This allows you to implement Clerk's functionality precisely where required without impacting the rest of your app. -The `` component must be added to your React entrypoint. +## Usage diff --git a/docs/guides/authjs-migration.mdx b/docs/guides/authjs-migration.mdx index 7ccf9daa74..82b0d2ae11 100644 --- a/docs/guides/authjs-migration.mdx +++ b/docs/guides/authjs-migration.mdx @@ -69,7 +69,9 @@ This guide shows how to migrate an application using Auth.js (formerly NextAuth. ### Wrap your Next.js app in `` - You will need to remove the `` provider from Auth.js and replace it with the `` provider from Clerk. `` will need to wrap your application, or wrap the portion of your app where you want to handle authentication. + Remove the `` provider from Auth.js and replace it with ``. + + ```tsx {{ filename: 'app/layout.tsx', mark: [1, 6, 10] }} diff --git a/docs/guides/waitlist.mdx b/docs/guides/waitlist.mdx index b1d25f2da8..0f3bffa54d 100644 --- a/docs/guides/waitlist.mdx +++ b/docs/guides/waitlist.mdx @@ -80,7 +80,9 @@ In [**Waitlist** mode](/docs/authentication/configuration/restrictions#waitlist) ### Add `` to your app - The [``](/docs/components/clerk-provider) component wraps your app to provide active session and user context to Clerk's hooks and other components. To use the `` component in your app, you must provide the `waitlistUrl` prop, which points to the URL of your waitlist page. + + + To use the `` component in your app, you must provide the `waitlistUrl` prop, which points to the URL of your waitlist page. ```tsx {{ filename: 'app/layout.tsx', mark: [6] }} import { ClerkProvider } from '@clerk/nextjs' diff --git a/docs/integrations/databases/convex.mdx b/docs/integrations/databases/convex.mdx index c98732de47..2c825606aa 100644 --- a/docs/integrations/databases/convex.mdx +++ b/docs/integrations/databases/convex.mdx @@ -112,9 +112,13 @@ This tutorial assumes that you have already [set up a Clerk application](/docs/q ### Configure the Clerk and Convex providers - Both Clerk and Convex have Provider components that are required to wrap your React application to provide the authentication and client context. + Both Clerk and Convex have provider components that are required to provide authentication and client context. - You may have already had a `` configured. Be sure that `` wraps `ConvexProviderWithClerk`, and that `useAuth` is passed to `ConvexProviderWithClerk`. + Clerk's provider component is ``, which should wrap your entire app at the entry point to make authentication globally accessible. See the [reference docs](/docs/components/clerk-provider) for other configuration options. + + Convex offers a provider that is specifically for integrating with Clerk called [``](https://docs.convex.dev/auth/clerk). + + The following example demonstrates how to configure Clerk and Convex's providers. Clerk's `useAuth()` hook must be passed to `` and Clerk's `` must be wrapped around it. ```ts {{ filename: 'src/main.tsx' }} import React from 'react' diff --git a/docs/quickstarts/chrome-extension.mdx b/docs/quickstarts/chrome-extension.mdx index fcc1493cae..3cb0d1d644 100644 --- a/docs/quickstarts/chrome-extension.mdx +++ b/docs/quickstarts/chrome-extension.mdx @@ -79,7 +79,7 @@ description: Add authentication and user management to your Chrome Extension wit ### Add `` to your app - All Clerk hooks and components must be children of the [``](/docs/components/clerk-provider) component, which provides active session and user context. Wrap your app in the `` component and pass your Publishable Key as a prop. + ```tsx {{ filename: 'src/popup.tsx', mark: [1, [7, 11], 15, 19] }} import { ClerkProvider } from '@clerk/chrome-extension' diff --git a/docs/quickstarts/expo.mdx b/docs/quickstarts/expo.mdx index 65d5069244..76500378d6 100644 --- a/docs/quickstarts/expo.mdx +++ b/docs/quickstarts/expo.mdx @@ -91,7 +91,9 @@ description: Add authentication and user management to your Expo app with Clerk. ### Add `` to your root layout - The [``](/docs/components/clerk-provider) component wraps your app to provide active session and user context to Clerk's hooks and other components. You must pass your Publishable Key as a prop to the `` component. + + + Pass your publishable key as a prop to the component. Clerk also provides [``](/docs/components/control/clerk-loaded), which won't render its children until the Clerk API has loaded. diff --git a/docs/quickstarts/nextjs.mdx b/docs/quickstarts/nextjs.mdx index e7e6e9f178..d7222bc320 100644 --- a/docs/quickstarts/nextjs.mdx +++ b/docs/quickstarts/nextjs.mdx @@ -97,7 +97,7 @@ description: Add authentication and user management to your Next.js app with Cle ### Add `` and Clerk components to your app - The [``](/docs/components/clerk-provider) component wraps your app to provide active session and user context to Clerk's hooks and other components. + You can control which content signed-in and signed-out users can see with Clerk's [prebuilt control components](/docs/components/overview#what-are-control-components). Create a header using the following components: diff --git a/docs/quickstarts/react.mdx b/docs/quickstarts/react.mdx index 7e04683d0c..9951acbcd9 100644 --- a/docs/quickstarts/react.mdx +++ b/docs/quickstarts/react.mdx @@ -119,7 +119,9 @@ description: Add authentication and user management to your React app with Clerk ### Add `` to your app - The [``](/docs/components/clerk-provider) component wraps your app to provide active session and user context to Clerk's hooks and other components. You must pass your Publishable Key as a prop to the `` component. + + + Pass your publishable key as a prop to the component. ```tsx {{ filename: 'src/main.tsx', mark: [5, 16, 18] }} import React from 'react' diff --git a/docs/quickstarts/tanstack-start.mdx b/docs/quickstarts/tanstack-start.mdx index 1e4ac7964b..4363013d83 100644 --- a/docs/quickstarts/tanstack-start.mdx +++ b/docs/quickstarts/tanstack-start.mdx @@ -94,7 +94,7 @@ description: Learn how to use Clerk to quickly and easily add secure authenticat ### Add `` to your app - The [``](/docs/components/clerk-provider) component wraps your app to provide active session and user context to Clerk's hooks and other components. + Add the `` component to your app's root route, as shown in the following example: From a24a17ffff91ec5a1d4ba6edfd46e9a967f1844a Mon Sep 17 00:00:00 2001 From: victoria Date: Fri, 6 Dec 2024 17:47:39 -0500 Subject: [PATCH 08/36] fix: formatting (#1782) --- docs/guides/authjs-migration.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/authjs-migration.mdx b/docs/guides/authjs-migration.mdx index 82b0d2ae11..f08dfd11e0 100644 --- a/docs/guides/authjs-migration.mdx +++ b/docs/guides/authjs-migration.mdx @@ -71,7 +71,7 @@ This guide shows how to migrate an application using Auth.js (formerly NextAuth. Remove the `` provider from Auth.js and replace it with ``. - + ```tsx {{ filename: 'app/layout.tsx', mark: [1, 6, 10] }} From 3b396ab2ab3f08bea987ff1a26576d5ca126c634 Mon Sep 17 00:00:00 2001 From: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> Date: Fri, 6 Dec 2024 18:27:05 -0500 Subject: [PATCH 09/36] update expo docs (#1666) Co-authored-by: victoria --- docs/_partials/expo/oauth-custom-flow.mdx | 58 ++ docs/custom-flows/email-password-mfa.mdx | 68 ++- docs/custom-flows/email-password.mdx | 230 +++----- docs/custom-flows/manage-totp-based-mfa.mdx | 56 +- docs/custom-flows/oauth-connections.mdx | 59 +- docs/custom-flows/sign-out.mdx | 28 +- docs/custom-flows/user-impersonation.mdx | 554 ++++++------------ docs/guides/custom-types.mdx | 4 +- docs/manifest.json | 42 +- docs/quickstarts/expo.mdx | 410 +++++++------ .../backend/types/backend-invitation.mdx | 2 +- .../types/backend-organization-invitation.mdx | 4 +- .../types/backend-organization-membership.mdx | 4 +- .../backend/types/backend-organization.mdx | 4 +- .../references/backend/types/backend-user.mdx | 6 +- docs/references/expo/overview.mdx | 25 +- .../expo/read-session-user-data.mdx | 13 +- docs/references/expo/use-oauth.mdx | 61 ++ .../javascript/external-account.mdx | 2 +- .../javascript/organization-invitation.mdx | 2 +- .../javascript/organization-membership.mdx | 2 +- .../javascript/organization/organization.mdx | 2 +- .../javascript/sign-up/authenticate-with.mdx | 4 +- .../references/javascript/sign-up/sign-up.mdx | 4 +- docs/references/javascript/types/metadata.mdx | 79 +++ docs/references/javascript/types/oauth.mdx | 10 +- .../types/user-organization-invitation.mdx | 2 +- docs/references/javascript/user/user.mdx | 8 +- docs/users/user-impersonation.mdx | 2 +- 29 files changed, 866 insertions(+), 879 deletions(-) create mode 100644 docs/_partials/expo/oauth-custom-flow.mdx create mode 100644 docs/references/expo/use-oauth.mdx create mode 100644 docs/references/javascript/types/metadata.mdx diff --git a/docs/_partials/expo/oauth-custom-flow.mdx b/docs/_partials/expo/oauth-custom-flow.mdx new file mode 100644 index 0000000000..81f09bee6c --- /dev/null +++ b/docs/_partials/expo/oauth-custom-flow.mdx @@ -0,0 +1,58 @@ +The following example demonstrates how to create a custom OAuth sign-in flow for [Google accounts](/docs/authentication/social-connections/google). + +```tsx {{ filename: 'app/(auth)/sign-in.tsx', collapsible: true }} +import React from 'react' +import * as WebBrowser from 'expo-web-browser' +import { Text, View, Button } from 'react-native' +import { Link } from 'expo-router' +import { useOAuth } from '@clerk/clerk-expo' +import * as Linking from 'expo-linking' + +export const useWarmUpBrowser = () => { + React.useEffect(() => { + // Warm up the android browser to improve UX + // https://docs.expo.dev/guides/authentication/#improving-user-experience + void WebBrowser.warmUpAsync() + return () => { + void WebBrowser.coolDownAsync() + } + }, []) +} + +WebBrowser.maybeCompleteAuthSession() + +export default function Page() { + useWarmUpBrowser() + + const { startOAuthFlow } = useOAuth({ strategy: 'oauth_google' }) + + const onPress = React.useCallback(async () => { + try { + const { createdSessionId, signIn, signUp, setActive } = await startOAuthFlow({ + redirectUrl: Linking.createURL('/dashboard', { scheme: 'myapp' }), + }) + + // If sign in was successful, set the active session + if (createdSessionId) { + setActive!({ session: createdSessionId }) + } else { + // Use signIn or signUp returned from startOAuthFlow + // for next steps, such as MFA + } + } catch (err) { + // See https://clerk.com/docs/custom-flows/error-handling + // for more info on error handling + console.error(JSON.stringify(err, null, 2)) + } + }, []) + + return ( + + + Home + + + ) } @@ -69,10 +69,10 @@ The following example shows two files: ```jsx {{ filename: 'app/sign-up/sso-callback/page.tsx' }} import { AuthenticateWithRedirectCallback } from '@clerk/nextjs' - export default function SSOCallback() { + export default function Page() { // Handle the redirect flow by rendering the // prebuilt AuthenticateWithRedirectCallback component. - // This is the final step in the custom SAML flow. + // This is the final step in the custom Enterprise SSO flow. return } ``` @@ -80,13 +80,13 @@ The following example shows two files: -## SAML account transfer flows +## Enterprise account transfer flows -It is common for users who are authenticating with SAML to use a sign-in button when they mean to sign-up, and vice versa. For those cases, the `SignIn` and `SignUp` objects have a `transferable` status that indicates whether the user can be transferred to the other flow. +It is common for users who are authenticating with an enterprise account to use a sign-in button when they mean to sign-up, and vice versa. For those cases, the `SignIn` and `SignUp` objects have a `transferable` status that indicates whether the user can be transferred to the other flow. **If you would like to keep your sign-in and sign-up flows completely separate, then you can skip this section.** -The following example demonstrates how to handle these cases in your sign-in flow. To apply the same logic to the sign-up flow, simply replace `signIn.authenticateWithRedirect()` with `signUp.authenticateWithRedirect()` in your code. +The following example demonstrates how to handle these cases in your sign-in flow. To apply the same logic to the sign-up flow, simply replace [`signIn.authenticateWithRedirect()`][sign-in-redirect] with [`signUp.authenticateWithRedirect()`][sign-up-redirect] in your code. @@ -96,13 +96,13 @@ The following example demonstrates how to handle these cases in your sign-in flo import * as React from 'react' import { useSignIn, useSignUp } from '@clerk/nextjs' - export default function SAMLSignIn() { + export default function Page() { const { signIn } = useSignIn() const { signUp, setActive } = useSignUp() if (!signIn || !signUp) return null - const signInWithSAML = (e: React.FormEvent) => { + const signInWithEnterpriseSSO = (e: React.FormEvent) => { e.preventDefault() const email = (e.target as HTMLFormElement).email.value @@ -110,7 +110,7 @@ The following example demonstrates how to handle these cases in your sign-in flo signIn .authenticateWithRedirect({ identifier: email, - strategy: 'saml', + strategy: 'enterprise_sso', redirectUrl: '/sso-callback', redirectUrlComplete: '/', }) @@ -127,7 +127,7 @@ The following example demonstrates how to handle these cases in your sign-in flo if (!signIn || !signUp) return null // If the user has an account in your application, but does not yet - // have a SAML account connected to it, you can transfer the SAML + // have a enterprise account connected to it, you can transfer the enterprise // account to the existing user account. const userExistsButNeedsToSignIn = signUp.verifications.externalAccount.status === 'transferable' && @@ -143,9 +143,9 @@ The following example demonstrates how to handle these cases in your sign-in flo } } - // If the user has a SAML account but does not yet + // If the user has a enterprise account but does not yet // have an account in your app, you can create an account - // for them using the SAML information. + // for them using the enterprise account's information. const userNeedsToBeCreated = signIn.firstFactorVerification.status === 'transferable' if (userNeedsToBeCreated) { @@ -160,18 +160,22 @@ The following example demonstrates how to handle these cases in your sign-in flo } } else { // If the user has an account in your application - // and has an SAML account connected to it, you can sign them in. - signInWithSAML(e) + // and has an enterprise account connected to it, you can sign them in. + signInWithEnterpriseSSO(e) } } return (
handleSignIn(e)}> - +
) } ```
+ +[sign-in-redirect]: /docs/references/javascript/sign-in/authenticate-with#authenticate-with-redirect + +[sign-up-redirect]: /docs/references/javascript/sign-up/authenticate-with#authenticate-with-redirect diff --git a/docs/manifest.json b/docs/manifest.json index 1952a20efe..7f84702730 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1673,8 +1673,8 @@ "href": "/docs/custom-flows/oauth-connections" }, { - "title": "SAML connections", - "href": "/docs/custom-flows/saml-connections" + "title": "Enterprise connections", + "href": "/docs/custom-flows/enterprise-connections" }, { "title": "Sign out", diff --git a/docs/references/javascript/sign-in/authenticate-with.mdx b/docs/references/javascript/sign-in/authenticate-with.mdx index bd7949b32c..f54ad008f2 100644 --- a/docs/references/javascript/sign-in/authenticate-with.mdx +++ b/docs/references/javascript/sign-in/authenticate-with.mdx @@ -19,16 +19,20 @@ function authenticateWithRedirect(params: AuthenticateWithRedirectParams): Promi - `strategy` - - [OAuthStrategy](/docs/references/javascript/types/oauth#o-auth-strategy) | 'saml' + - [OAuthStrategy](/docs/references/javascript/types/oauth#o-auth-strategy) | 'saml' | 'enterprise\_sso' - The strategy corresponding to the OAuth provider. For example: `oauth_facebook`, `oauth_github`, etc. + The strategy to use for authentication. The following strategies are supported: + + - `oauth_`: The user will be authenticated with their social sign-in account. [See available social providers](/docs/references/javascript/types/oauth#o-auth-provider). + - `saml`: The user will be authenticated with SAML. **Deprecated in favor of `enterprise_sso`.** + - `enterprise_sso`: The user will be authenticated either through SAML or OIDC, depending on the configuration of the [enterprise connection](/docs/authentication/enterprise-connections/overview) matching the identifier. --- - `redirectUrl` - `string` - Full URL or path to the route that will complete the OAuth or SAML flow. Typically, this will be a simple `/sso-callback` route that calls `Clerk.handleRedirectCallback` or mounts the `` component. + The full URL or path to the route that will complete the OAuth or SAML flow. Typically, this will be a simple `/sso-callback` route that calls `Clerk.handleRedirectCallback` or mounts the `` component. --- @@ -36,6 +40,13 @@ function authenticateWithRedirect(params: AuthenticateWithRedirectParams): Promi - `string` The URL that the user will be redirected to, after successful authorization from the OAuth provider and Clerk sign in. + + --- + + - `identifier` + - `string | undefined` + + Identifier to use for targeting an enterprise connection at sign-in. ### `authenticateWithMetamask()` diff --git a/docs/references/javascript/sign-up/authenticate-with.mdx b/docs/references/javascript/sign-up/authenticate-with.mdx index c98405e5ad..3b20ac50ff 100644 --- a/docs/references/javascript/sign-up/authenticate-with.mdx +++ b/docs/references/javascript/sign-up/authenticate-with.mdx @@ -38,26 +38,27 @@ function authenticateWithRedirect(params: AuthenticateWithRedirectParams): Promi --- - `strategy` - - `'oauth_' | 'saml'` + - `'oauth_' | 'saml' | 'enterprise_sso'` The strategy to use for authentication. The following strategies are supported: - `oauth_`: The user will be authenticated with their social sign-in account. [See available social providers](/docs/references/javascript/types/oauth#o-auth-provider). - - `saml`: The user will be authenticated with SAML. + - `saml`: The user will be authenticated with SAML. **Deprecated** + - `enterprise_sso`: The user will be authenticated either through SAML or OIDC, depending on the configuration of the [enterprise connection](/docs/authentication/enterprise-connections/overview) matching the identifier. --- - `identifier` - `string | undefined` - Identifier to use for targeting a SAML connection at sign-up. + Identifier to use for targeting an enterprise connection at sign-up. --- - `emailAddress` - `string | undefined` - Email address to use for targeting a SAML connection at sign-up. + Email address to use for targeting an enterprise connection at sign-up. --- diff --git a/docs/references/javascript/sign-up/verification.mdx b/docs/references/javascript/sign-up/verification.mdx index 7a15cb0e2c..9c1c158aec 100644 --- a/docs/references/javascript/sign-up/verification.mdx +++ b/docs/references/javascript/sign-up/verification.mdx @@ -20,14 +20,15 @@ function prepareVerification(params: PrepareVerificationParams): Promise - `strategy` - - `'phone_code' | 'email_code' | 'email_link' | 'saml' | 'oauth_' | 'web3_metamask_signature' | 'web3_coinbase_wallet_signature'` + - `'phone_code' | 'email_code' | 'email_link' | 'saml' | 'enterprise_sso' | 'oauth_' | 'web3_metamask_signature' | 'web3_coinbase_wallet_signature'` The verification strategy to validate the user's sign-up request. The following strategies are supported: - `phone_code`: Send an SMS with a unique token to input. - `email_code`: Send an email with a unique token to input. - `email_link`: Send an email with a link which validates sign-up - - `saml`: The user will be authenticated with SAML. **Experimental** + - `saml`: The user will be authenticated with SAML. **Deprecated in favor of `enterprise_sso`.** + - `enterprise_sso`: The user will be authenticated either through SAML or OIDC depending on the configuration of the [enterprise connection](/docs/authentication/enterprise-connections/overview) matching the identifier. - `oauth_`: The user will be authenticated with their social sign-in account. [See available social providers](/docs/references/javascript/types/oauth#o-auth-provider). - `web3_metamask_signature`: The verification will attempt to be completed using the user's Web3 wallet address via [Metamask](https://metamask.io/). The `web3_wallet_id` parameter can also be specified to select which of the user's known Web3 wallets will be used. - `web3_coinbase_wallet_signature`: The verification will attempt to be completed using the user's Web3 wallet address via [Coinbase Wallet](https://www.coinbase.com/wallet). The `web3_wallet_id` parameter can also be specified to select which of the user's known Web3 wallets will be used. diff --git a/docs/references/javascript/types/verification.mdx b/docs/references/javascript/types/verification.mdx index c0955b8f32..432df00c99 100644 --- a/docs/references/javascript/types/verification.mdx +++ b/docs/references/javascript/types/verification.mdx @@ -48,7 +48,7 @@ An interface that represents the state of the verification process of a sign-in - `unverified`: The verification has not been verified yet. - `verified`: The verification has been verified. - - `transferable`: The verification is transferable to between sign-in and sign-up flows. This status is to be used in [OAuth](/docs/custom-flows/oauth-connections#o-auth-account-transfer-flows) and [SAML](/docs/custom-flows/saml-connections#saml-account-transfer-flows) authentication flows. + - `transferable`: The verification is transferable to between sign-in and sign-up flows. This status is to be used in [OAuth](/docs/custom-flows/oauth-connections#o-auth-account-transfer-flows) and [Enterprise SSO](/docs/custom-flows/enterprise-connections#enterprise-account-transfer-flows) authentication flows. - `failed`: The verification has failed. - `expired`: The verification has expired. From e960d6cbbfa573619f4a2c2b2140c3217dcd7c3f Mon Sep 17 00:00:00 2001 From: Haris Chaniotakis Date: Tue, 10 Dec 2024 18:17:02 +0200 Subject: [PATCH 15/36] Introduce OKX Wallet Web3 provider and authentication strategy (#1768) Co-authored-by: victoria Co-authored-by: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> --- .../configuration/sign-up-sign-in-options.mdx | 4 +- .../elements/reference/sign-in.mdx | 4 +- docs/references/javascript/clerk/clerk.mdx | 81 ++++++++++++++----- .../javascript/sign-in/authenticate-with.mdx | 8 ++ .../javascript/sign-in/first-factor.mdx | 4 +- .../references/javascript/sign-in/sign-in.mdx | 2 + .../javascript/sign-up/authenticate-with.mdx | 17 ++-- .../references/javascript/sign-up/sign-up.mdx | 1 + .../javascript/sign-up/verification.mdx | 6 +- .../javascript/sign-up/web3-verification.mdx | 2 + .../javascript/types/sign-in-first-factor.mdx | 5 +- .../javascript/web3-wallet/verification.mdx | 2 + .../javascript/web3-wallet/web3-wallet.mdx | 2 +- docs/references/react/use-sign-in.mdx | 2 +- docs/users/web3.mdx | 8 +- 15 files changed, 108 insertions(+), 40 deletions(-) diff --git a/docs/authentication/configuration/sign-up-sign-in-options.mdx b/docs/authentication/configuration/sign-up-sign-in-options.mdx index 6e4865727a..989bfceca5 100644 --- a/docs/authentication/configuration/sign-up-sign-in-options.mdx +++ b/docs/authentication/configuration/sign-up-sign-in-options.mdx @@ -162,12 +162,12 @@ To enable social connections: ## Web3 authentication -Clerk provides [Web3 authentication](/docs/users/web3) with either MetaMask or Coinbase Wallet. As part of validating the accuracy of the returned Web3 account address, Clerk handles the signing of a message and verifying the signature. Because sign-in with Web3 uses the same abstraction as our other authentication factors, like passwords or email links, other Clerk features like multi-factor authentication and profile enrichment work for Web3 users out-of-the-box. +Clerk provides [Web3 authentication](/docs/users/web3) with either MetaMask, Coinbase Wallet or OKX Wallet. As part of validating the accuracy of the returned Web3 account address, Clerk handles the signing of a message and verifying the signature. Because sign-in with Web3 uses the same abstraction as our other authentication factors, like passwords or email links, other Clerk features like multi-factor authentication and profile enrichment work for Web3 users out-of-the-box. To enable Web3 authentication: 1. In the Clerk Dashboard, navigate to the [**Web3**](https://dashboard.clerk.com/last-active?path=user-authentication/web3) page. -1. Toggle on the Web3 provider. Currently, Clerk supports MetaMask and Coinbase Wallet. +1. Enable your preferred Web3 provider. ## Multi-factor authentication diff --git a/docs/customization/elements/reference/sign-in.mdx b/docs/customization/elements/reference/sign-in.mdx index 0dae331b7c..0594c731ef 100644 --- a/docs/customization/elements/reference/sign-in.mdx +++ b/docs/customization/elements/reference/sign-in.mdx @@ -166,7 +166,7 @@ Conditionally renders its children depending on the authentication strategy that - `name` - - 'saml' | 'ticket' | 'password' | 'passkey' | 'phone\_code' | 'email\_code' | 'web3\_metamask\_signature' | 'web3\_coinbase\_wallet\_signature' | 'reset\_password\_email\_code' | 'reset\_password\_phone\_code' | 'email\_link' | 'totp' | 'backup\_code' | 'oauth' | 'web3' | [OAuthStrategy](https://github.com/clerk/javascript/blob/956d8792fefe9d6a89022f1e938149b25503ec7f/packages/types/src/strategies.ts#L15) + - 'saml' | 'ticket' | 'password' | 'passkey' | 'phone\_code' | 'email\_code' | 'web3\_metamask\_signature' | 'web3\_coinbase\_wallet\_signature' | 'web3\_okx\_wallet\_signature' | 'reset\_password\_email\_code' | 'reset\_password\_phone\_code' | 'email\_link' | 'totp' | 'backup\_code' | 'oauth' | 'web3' | [OAuthStrategy](https://github.com/clerk/javascript/blob/956d8792fefe9d6a89022f1e938149b25503ec7f/packages/types/src/strategies.ts#L15) The name of the strategy for which its children will be rendered. @@ -200,7 +200,7 @@ Renders a button that will change the current strategy that needs to be verified - `name` - - `'email_code' | 'email_link' | 'password' | 'passkey' | 'phone_code' | 'reset_password_email_code' | 'reset_password_phone_code' | 'web3_metamask_signature' | 'web3_coinbase_wallet_signature'` + - `'email_code' | 'email_link' | 'password' | 'passkey' | 'phone_code' | 'reset_password_email_code' | 'reset_password_phone_code' | 'web3_metamask_signature' | 'web3_coinbase_wallet_signature' | 'web3_okx_wallet_signature'` The name of the strategy to switch to. diff --git a/docs/references/javascript/clerk/clerk.mdx b/docs/references/javascript/clerk/clerk.mdx index 05425728ea..57522e3841 100644 --- a/docs/references/javascript/clerk/clerk.mdx +++ b/docs/references/javascript/clerk/clerk.mdx @@ -148,21 +148,21 @@ function authenticateWithMetamask({ - `redirectUrl?` - `string | undefined` - Full URL or path to navigate to after a successful sign in or sign up. + The full URL or path to navigate to after a successful sign in or sign up. --- - `signUpContinueUrl?` - `string | undefined` - The location to continue navigation to in the sign up process if data is missing. + The URL to navigate to in the sign-up process if data is missing. --- - `customNavigate?` - `((to: string) => Promise | unknown) | undefined` - Allows you to define a custom navigation function + A function that overrides Clerk's default navigation behavior, allowing custom handling of navigation during sign-up and sign-in flows. ### `authenticateWithCoinbaseWallet()` @@ -181,21 +181,66 @@ function authenticateWithCoinbaseWallet({ - `redirectUrl?` - `string | undefined` - Full URL or path to navigate to after a successful sign in or sign up. + The full URL or path to navigate to after a successful sign in or sign up. --- - `signUpContinueUrl?` - `string | undefined` - The location to continue navigation to in the sign up process if data is missing. + The full URL or path to navigate to in the sign-up process if data is missing. --- - `customNavigate?` - `((to: string) => Promise | unknown) | undefined` - Allows you to define a custom navigation function + A function that overrides Clerk's default navigation behavior, allowing custom handling of navigation during sign-up and sign-in flows. + + +### `authenticateWithOKXWallet()` + +Starts a sign-in flow that uses the OKX Wallet to authenticate the user using their Web3 wallet address. + +```typescript +function authenticateWithOKXWallet(props?: AuthenticateWithOKXWalletParams): Promise +``` + +#### `AuthenticateWithOKXWalletParams` + + + - `redirectUrl?` + - `string | undefined` + + The full URL or path to navigate to after a successful sign-in or sign-up. + + --- + + - `signUpContinueUrl?` + - `string | undefined` + + The full URL or path to navigate to in the sign-up process if data is missing. + + --- + + - `customNavigate?` + - `((to: string) => Promise | unknown) | undefined` + + A function that overrides Clerk's default navigation behavior, allowing custom handling of navigation during sign-up and sign-in flows. + + --- + + - `unsafeMetadata?` + - [`SignUpUnsafeMetadata`](/docs/references/javascript/types/metadata#sign-up-unsafe-metadata) + + Metadata that can be read and set from the frontend. Once the sign-up is complete, the value of this field will be automatically copied to the newly created user's unsafe metadata. One common use case for this attribute is to use it to implement custom fields that can be collected during sign-up and will automatically be attached to the created `User` object. + + --- + + - `legalAccepted?` + - `boolean` + + The user has agreed to the [legal compliance](/docs/authentication/configuration/legal-compliance) documents. ### `authenticateWithWeb3()` @@ -215,21 +260,21 @@ function authenticateWithWeb3({ - `redirectUrl?` - `string | undefined` - Full URL or path to navigate to after a successful sign in or sign up. + The full URL or path to navigate to after a successful sign in or sign up. --- - `signUpContinueUrl?` - `string | undefined` - The location to continue navigation to in the sign up process if data is missing. + The full URL or path to navigate to in the sign-up process if data is missing. --- - `customNavigate?` - `((to: string) => Promise | unknown) | undefined` - Allows you to define a custom navigation function + A function that overrides Clerk's default navigation behavior, allowing custom handling of navigation during sign-up and sign-in flows. --- @@ -264,7 +309,7 @@ class Clerk { - `options?` - [DomainOrProxyUrl](#domain-or-proxy-url) | undefined - The domain or proxy URL used to connect to Clerk + The domain or proxy URL used to connect to Clerk. #### `DomainOrProxyUrl` @@ -275,14 +320,14 @@ Only one of the two properties are allowed to be set at a time. - `proxyUrl?` - `never | string | ((url: URL) => string)` - The proxy URL used to connect to Clerk. If a function, will be called with a `URL` made from `window.location.href` + The proxy URL used to connect to Clerk. If a function, will be called with a `URL` made from `window.location.href`. --- - `domain?` - `never | string | ((url: URL) => string)` - The domain used to connect to Clerk. If a function, will be called with a `URL` made from `window.location.href` + The domain used to connect to Clerk. If a function, will be called with a `URL` made from `window.location.href`. ### `load()` @@ -331,7 +376,7 @@ All props below are optional. - `polling` - `boolean | undefined` - Dictates if we should poll against Clerk's backend every 5 minutes. Defaults to `true` + Dictates if we should poll against Clerk's backend every 5 minutes. Defaults to `true`. --- @@ -345,21 +390,21 @@ All props below are optional. - `standardBrowser` - `boolean | undefined` - Controls if ClerkJS will load with the standard browser set up using Clerk cookies. Defaults to `true` + Controls if ClerkJS will load with the standard browser set up using Clerk cookies. Defaults to `true`. --- - `supportEmail` - `string | undefined` - Optional support email for display in authentication screens + Optional support email for display in authentication screens. --- - `touchSession` - `boolean | undefined` - Indicates whether the session should be "touched" when user interactions occur, used to record these interactions. Defaults to `true` + Indicates whether the session should be "touched" when user interactions occur, used to record these interactions. Defaults to `true`. --- @@ -422,7 +467,7 @@ All props below are optional. - `isSatellite` - `boolean | ((url: URL) => boolean) | undefined` - Clerk Flag for satellite apps. Experimental. + Clerk flag for satellite apps. Experimental. --- @@ -461,7 +506,7 @@ function signOut( - `redirectUrl?` - `string` - Full URL or path to navigate to after sign out is complete. + The full URL or path to navigate to after sign out is complete. ## Components diff --git a/docs/references/javascript/sign-in/authenticate-with.mdx b/docs/references/javascript/sign-in/authenticate-with.mdx index f54ad008f2..de335f09e1 100644 --- a/docs/references/javascript/sign-in/authenticate-with.mdx +++ b/docs/references/javascript/sign-in/authenticate-with.mdx @@ -77,6 +77,14 @@ function authenticateWithCoinbaseWallet(): Promise | - | - | | `Promise` | A `Promise` which resolves to the current [`SignIn`][signin-ref]. | +### `authenticateWithOKXWallet()` + +Starts a sign-in flow that uses the OKX Wallet to authenticate the user using their Web3 wallet address. Returns a `Promise` which resolves to the current [`SignIn`][signin-ref]. + +```typescript +function authenticateWithOKXWallet(): Promise +``` + ### `authenticateWithWeb3()` Starts a sign-in flow that authenticates the user against their Web3 wallet address. diff --git a/docs/references/javascript/sign-in/first-factor.mdx b/docs/references/javascript/sign-in/first-factor.mdx index 424004f283..2191b569ca 100644 --- a/docs/references/javascript/sign-in/first-factor.mdx +++ b/docs/references/javascript/sign-in/first-factor.mdx @@ -28,6 +28,7 @@ function prepareFirstFactor(params: PrepareFirstFactorParams): Promise - `phone_code`: User will receive a one-time authentication code in their phone, via SMS. At least one phone number should be on file for the user. The `phone_number_id` parameter can also be specified to select which of the user's known phone numbers the SMS will go to. - `web3_metamask_signature`: The verification will attempt to be completed using the user's Web3 wallet address via [Metamask](https://metamask.io/). The `web3_wallet_id` parameter can also be specified to select which of the user's known Web3 wallets will be used. - `web3_coinbase_wallet_signature`: The verification will attempt to be completed using the user's Web3 wallet address via [Coinbase Wallet](https://www.coinbase.com/wallet). The `web3_wallet_id` parameter can also be specified to select which of the user's known Web3 wallets will be used. + - `web3_okx_wallet_signature`: The verification will attempt to be completed using the user's Web3 wallet address via [OKX Wallet](https://www.okx.com/help/section/faq-web3-wallet). The `web3_wallet_id` parameter can also be specified to select which of the user's known Web3 wallets will be used. - `oauth_`: The user will be authenticated with their social sign-in account. [See available social providers](/docs/references/javascript/types/oauth#o-auth-provider). --- @@ -49,7 +50,7 @@ function prepareFirstFactor(params: PrepareFirstFactorParams): Promise - `web3WalletId?` - `string` - Unique identifier for the user's Web3 wallet address. This parameter will work only when the `web3_metamask_signature` or `web3_coinbase_wallet_signature` strategy is specified. + Unique identifier for the user's Web3 wallet address. This parameter will work only when the `strategy` is set to `web3_metamask_signature`, `web3_coinbase_wallet_signature`, or `web3_okx_wallet_signature`. --- @@ -97,6 +98,7 @@ function attemptFirstFactor(params: AttemptFirstFactorParams): Promise - `'password'`: The verification will attempt to be completed with the user's password. - `'web3_metamask_signature'`: The verification will attempt to be completed using the user's Web3 wallet address via [Metamask](https://metamask.io/). - `'web3_coinbase_wallet_signature'`: The verification will attempt to be completed using the user's Web3 wallet address via [Coinbase Wallet](https://www.coinbase.com/wallet). + - `'web3_okx_wallet_signature'`: The verification will attempt to be completed using the user's Web3 wallet address via [OKX Wallet](https://www.okx.com/help/section/faq-web3-wallet). - `'passkey'`: The verification will attempt to be completed using the user's passkey. - `'reset_password_phone_code'`: Used when the user is trying to reset their password. The user will receive a one-time code via SMS. - `'reset_password_email_code'`: Used when the user is trying to reset their password. The user will receive a one-time code via email. diff --git a/docs/references/javascript/sign-in/sign-in.mdx b/docs/references/javascript/sign-in/sign-in.mdx index f435a46aaf..9eac85f5f2 100644 --- a/docs/references/javascript/sign-in/sign-in.mdx +++ b/docs/references/javascript/sign-in/sign-in.mdx @@ -128,6 +128,7 @@ function create(params: SignInCreateParams): Promise - `phone_code`: User will receive a one-time authentication code in their phone, via SMS. At least one phone number should be on file for the user. The `phone_number_id` parameter can also be specified to select which of the user's known phone numbers the SMS will go to. - `web3_metamask_signature`: The verification will attempt to be completed using the user's Web3 wallet address via [Metamask](https://metamask.io/). The `web3_wallet_id` parameter can also be specified to select which of the user's known Web3 wallets will be used. - `web3_coinbase_wallet_signature`: The verification will attempt to be completed using the user's Web3 wallet address via [Coinbase Wallet](https://www.coinbase.com/wallet). The `web3_wallet_id` parameter can also be specified to select which of the user's known Web3 wallets will be used. + - `web3_okx_wallet_signature`: The verification will attempt to be completed using the user's Web3 wallet address via [OKX Wallet](https://www.okx.com/help/section/faq-web3-wallet). The `web3_wallet_id` parameter can also be specified to select which of the user's known Web3 wallets will be used. - `oauth_`: The user will be authenticated with their social sign-in account. [See available social providers](/docs/references/javascript/types/oauth#o-auth-provider). - `ticket`: The user will be authenticated via the ticket _or token_ generated from the Backend API. - `google_one_tap`: The user will be authenticated with the Google One Tap UI. It's recommended to use [`authenticateWithGoogleOneTap()`](/docs/components/authentication/google-one-tap#authenticate-with-google-one-tap) instead, as it will also set the user's current session as active for you. @@ -258,6 +259,7 @@ In addition to the methods listed above, the `SignIn` class also has the followi - [`authenticateWithRedirect()`](/docs/references/javascript/sign-in/authenticate-with#authenticate-with-redirect) - [`authenticateWithMetamask()`](/docs/references/javascript/sign-in/authenticate-with#authenticate-with-metamask) - [`authenticateWithCoinbaseWallet()`](/docs/references/javascript/sign-in/authenticate-with#authenticate-with-coinbase-wallet) +- [`authenticateWithOKXWallet()`](/docs/references/javascript/sign-in/authenticate-with#authenticate-with-okx-wallet) - [`authenticateWithWeb3()`](/docs/references/javascript/sign-in/authenticate-with#authenticate-with-web3) ## Example diff --git a/docs/references/javascript/sign-up/authenticate-with.mdx b/docs/references/javascript/sign-up/authenticate-with.mdx index 3b20ac50ff..60c9f35c44 100644 --- a/docs/references/javascript/sign-up/authenticate-with.mdx +++ b/docs/references/javascript/sign-up/authenticate-with.mdx @@ -172,6 +172,16 @@ function authenticateWithCoinbaseWallet( ): Promise ``` +## `authenticateWithOKXWallet()` + +Starts a sign-up flow that uses the OKX Wallet to authenticate the user using their public Web3 wallet address. + +```typescript +function authenticateWithOKXWallet( + params?: SignUpAuthenticateWithWeb3Params, +): Promise +``` + ### `SignUpAuthenticateWithWeb3Params` @@ -179,13 +189,6 @@ function authenticateWithCoinbaseWallet( - [`SignUpUnsafeMetadata`](/docs/references/javascript/types/metadata#sign-up-unsafe-metadata) Custom fields that will be attached to the [`User`](/docs/references/javascript/user/user) object post-signup. - - --- - - - `legalAccepted?` - - `boolean` - - The user has agreed to the [legal compliance](/docs/authentication/configuration/legal-compliance) documents. [signup-ref]: /docs/references/javascript/sign-up/sign-up diff --git a/docs/references/javascript/sign-up/sign-up.mdx b/docs/references/javascript/sign-up/sign-up.mdx index 52ac67d571..94a3311c4d 100644 --- a/docs/references/javascript/sign-up/sign-up.mdx +++ b/docs/references/javascript/sign-up/sign-up.mdx @@ -338,6 +338,7 @@ In addition to the methods listed above, the `SignUp` class also has the followi - [`authenticateWithRedirect()`](/docs/references/javascript/sign-up/authenticate-with#authenticate-with-redirect) - [`authenticateWithMetamask()`](/docs/references/javascript/sign-up/authenticate-with#authenticate-with-metamask) - [`authenticateWithCoinbaseWallet()`](/docs/references/javascript/sign-up/authenticate-with#authenticate-with-coinbase-wallet) +- [`authenticateWithOKXWallet()`](/docs/references/javascript/sign-up/authenticate-with#authenticate-with-okx-wallet) - [`authenticateWithWeb3()`](/docs/references/javascript/sign-up/authenticate-with#authenticate-with-web3) ### Verification diff --git a/docs/references/javascript/sign-up/verification.mdx b/docs/references/javascript/sign-up/verification.mdx index 9c1c158aec..56ac49d739 100644 --- a/docs/references/javascript/sign-up/verification.mdx +++ b/docs/references/javascript/sign-up/verification.mdx @@ -20,7 +20,7 @@ function prepareVerification(params: PrepareVerificationParams): Promise - `strategy` - - `'phone_code' | 'email_code' | 'email_link' | 'saml' | 'enterprise_sso' | 'oauth_' | 'web3_metamask_signature' | 'web3_coinbase_wallet_signature'` + - `'phone_code' | 'email_code' | 'email_link' | 'saml' | 'enterprise_sso' | 'oauth_' | 'web3_metamask_signature' | 'web3_coinbase_wallet_signature' | 'web3_okx_wallet_signature'` The verification strategy to validate the user's sign-up request. The following strategies are supported: @@ -32,6 +32,7 @@ function prepareVerification(params: PrepareVerificationParams): Promise`: The user will be authenticated with their social sign-in account. [See available social providers](/docs/references/javascript/types/oauth#o-auth-provider). - `web3_metamask_signature`: The verification will attempt to be completed using the user's Web3 wallet address via [Metamask](https://metamask.io/). The `web3_wallet_id` parameter can also be specified to select which of the user's known Web3 wallets will be used. - `web3_coinbase_wallet_signature`: The verification will attempt to be completed using the user's Web3 wallet address via [Coinbase Wallet](https://www.coinbase.com/wallet). The `web3_wallet_id` parameter can also be specified to select which of the user's known Web3 wallets will be used. + - `web3_okx_wallet_signature`: The verification will attempt to be completed using the user's Web3 wallet address via [OKX Wallet](https://www.okx.com/help/section/faq-web3-wallet). The `web3_wallet_id` parameter can also be specified to select which of the user's known Web3 wallets will be used. --- @@ -55,7 +56,7 @@ function attemptVerification(params: AttemptVerificationParams): Promise - `strategy` - - `'phone_code' | 'email_code' | 'web3_metamask_signature' | 'web3_coinbase_wallet_signature'` + - `'phone_code' | 'email_code' | 'web3_metamask_signature' | 'web3_coinbase_wallet_signature' | 'web3_okx_wallet_signature'` The verification strategy to complete the user's sign-up request against. The following strategies are supported: @@ -63,6 +64,7 @@ function attemptVerification(params: AttemptVerificationParams): Promise - `email_code`: Validates an email with a unique token to input. - `web3_metamask_signature`: The verification will attempt to be completed using the user's Web3 wallet address via [Metamask](https://metamask.io/). The `web3_wallet_id` parameter can also be specified to select which of the user's known Web3 wallets will be used. - `web3_coinbase_wallet_signature`: The verification will attempt to be completed using the user's Web3 wallet address via [Coinbase Wallet](https://www.coinbase.com/wallet). The `web3_wallet_id` parameter can also be specified to select which of the user's known Web3 wallets will be used. + - `web3_okx_wallet_signature`: The verification will attempt to be completed using the user's Web3 wallet address via [OKX Wallet](https://www.okx.com/help/section/faq-web3-wallet). The `web3_wallet_id` parameter can also be specified to select which of the user's known Web3 wallets will be used. --- diff --git a/docs/references/javascript/sign-up/web3-verification.mdx b/docs/references/javascript/sign-up/web3-verification.mdx index e938b76c33..e20aad4e3b 100644 --- a/docs/references/javascript/sign-up/web3-verification.mdx +++ b/docs/references/javascript/sign-up/web3-verification.mdx @@ -23,11 +23,13 @@ function prepareWeb3WalletVerification( - `strategy` - `'web3_metamask_signature'` - `'web3_coinbase_wallet_signature'` + - `'web3_okx_wallet_signature'` The verification strategy to validate the user's sign-up request. The following strategies are supported: - `web3_metamask_signature`: User will need to sign a message and generate a signature using MetaMask browser extension. - `web3_coinbase_wallet_signature`: User will need to sign a message and generate a signature using Coinbase Wallet. + - `web3_okx_wallet_signature`: User will need to sign a message and generate a signature using OKX Wallet. ## `attemptWeb3WalletVerification()` diff --git a/docs/references/javascript/types/sign-in-first-factor.mdx b/docs/references/javascript/types/sign-in-first-factor.mdx index 1d5fc7a6fc..8e4d3892fa 100644 --- a/docs/references/javascript/types/sign-in-first-factor.mdx +++ b/docs/references/javascript/types/sign-in-first-factor.mdx @@ -32,6 +32,7 @@ type SignInFirstFactor = - `"reset_password_email_code"` - `"web3_metamask_signature"` - `"web3_coinbase_wallet_signature"` + - `"web3_okx_wallet_signature"` - [`OAuthStrategy`](/docs/references/javascript/types/oauth) - `"saml"` @@ -54,7 +55,7 @@ type SignInFirstFactor = - `web3WalletId` - `string` - The ID of the Web3 wallet that will be used to sign a message. Populated when the `strategy` is `"web3_metamask_signature"` or `"web3_coinbase_wallet_signature"`. + The ID of the Web3 wallet that will be used to sign a message. Populated when the `strategy` is `"web3_metamask_signature"`, `"web3_coinbase_wallet_signature"`, or `"web3_okx_wallet_signature"`. --- @@ -73,7 +74,7 @@ type SignInFirstFactor = - `primary` - `boolean` - Whether the factor is the primary factor.
Populated when the strategy is `"email_code"`, `"email_link"`, `"phone_code"`, `"web3_metamask_signature"`, `"web3_coinbase_wallet_signature"`, `"reset_password_email_code"`, or `"reset_password_phone_code"`. + Whether the factor is the primary factor.
Populated when the strategy is `"email_code"`, `"email_link"`, `"phone_code"`, `"web3_metamask_signature"`, `"web3_coinbase_wallet_signature"`, `"web3_okx_wallet_signature"`, `"reset_password_email_code"`, or `"reset_password_phone_code"`. ## `EmailCodeFactor` diff --git a/docs/references/javascript/web3-wallet/verification.mdx b/docs/references/javascript/web3-wallet/verification.mdx index d993b853d1..a3931c3d49 100644 --- a/docs/references/javascript/web3-wallet/verification.mdx +++ b/docs/references/javascript/web3-wallet/verification.mdx @@ -19,11 +19,13 @@ function prepareVerification(params: PrepareWeb3WalletVerificationParams): Promi - `strategy` - `'web3_metamask_signature'` - `'web3_coinbase_wallet_signature'` + - `'web3_okx_wallet_signature'` The verification strategy. Possible strategy values are: - `web3_metamask_signature`: User will need to sign a message and generate a signature using MetaMask browser extension. - `web3_coinbase_wallet_signature`: User will need to sign a message and generate a signature using Coinbase Wallet. + - `web3_okx_wallet_signature`: User will need to sign a message and generate a signature using OKX Wallet. ### `prepareVerification()` returns diff --git a/docs/references/javascript/web3-wallet/web3-wallet.mdx b/docs/references/javascript/web3-wallet/web3-wallet.mdx index 7d3859e005..42591c0f61 100644 --- a/docs/references/javascript/web3-wallet/web3-wallet.mdx +++ b/docs/references/javascript/web3-wallet/web3-wallet.mdx @@ -5,7 +5,7 @@ description: The Web3Wallet object describes a Web3 wallet address. The address The `Web3Wallet` object describes a Web3 wallet address. The address can be used as a proof of identification for users. -Web3 addresses must be verified to ensure that they can be assigned to their rightful owners. The verification is completed via Web3 wallet browser extensions, such as [Metamask](https://metamask.io/) and [Coinbase Wallet](https://www.coinbase.com/wallet). The `Web3Wallet3` object holds all the necessary state around the verification process. +Web3 addresses must be verified to ensure that they can be assigned to their rightful owners. The verification is completed via Web3 wallet browser extensions, such as [Metamask](https://metamask.io/), [Coinbase Wallet](https://www.coinbase.com/wallet), and [OKX Wallet](https://www.okx.com/help/section/faq-web3-wallet). The `Web3Wallet3` object holds all the necessary state around the verification process. The verification process always starts with the [`Web3Wallet.prepareVerification()`](/docs/references/javascript/web3-wallet/verification#prepare-verification) or [`signIn.prepareFirstFactor()`](/docs/references/javascript/sign-in/first-factor#prepare-first-factor) method, which will send the wallet address to the [Frontend API](/docs/reference/frontend-api){{ target: '_blank' }} and will receive a nonce that needs to be signed by the Web3 wallet browser extension. diff --git a/docs/references/react/use-sign-in.mdx b/docs/references/react/use-sign-in.mdx index c178a6a80d..aa194cb672 100644 --- a/docs/references/react/use-sign-in.mdx +++ b/docs/references/react/use-sign-in.mdx @@ -77,7 +77,7 @@ The `status` property of the `SignIn` object can be one of the following values: | Values | Descriptiom | | - | - | | `complete` | The user has been signed in and custom flow can proceed to `setActive()` to create session. | -| `needs_first_factor` | The First Factor verification is missing. One of `email_link`, `email_code`, `phone_code`, `web3_metamask_signature`, `web3_coinbase_wallet_signature` or `oauth_provider` is required to verify user. See [First Factor](/docs/references/javascript/sign-in/first-factor) for details. | +| `needs_first_factor` | The first factor verification is missing. One of `email_link`, `email_code`, `phone_code`, `web3_metamask_signature`, `web3_coinbase_wallet_signature`, `web3_okx_wallet_signature` or `oauth_provider` is required to verify the user. See [the reference](/docs/references/javascript/sign-in/first-factor) for more information. | | `needs_second_factor` | The Second Factor verification is missing. The Second Factor is an optional step to provide additional verification and includes `phone_code` and `totp`. See [Second Factor](/docs/references/javascript/sign-in/second-factor) for details. | | `needs_identifier` | The user's identifier (email address, phone number, username, etc.) hasn't been provided. | | `needs_new_password` | The user needs to set a new password. | diff --git a/docs/users/web3.mdx b/docs/users/web3.mdx index cb5f89563b..a823fee5ae 100644 --- a/docs/users/web3.mdx +++ b/docs/users/web3.mdx @@ -7,9 +7,9 @@ Learn how to use Clerk to quickly and easily add secure authentication and user ## Before you start -You need to create a Clerk application in the [Clerk Dashboard](https://dashboard.clerk.com/) and configure the application to use **Sign in with Metamask** or **Sign in with Coinbase Wallet**. For more information on how to set up a Clerk application, see the [setup guide](/docs/quickstarts/setup-clerk). To enable Metamask or Coinbase Wallet authentication, see the [dedicated guide](/docs/authentication/configuration/sign-up-sign-in-options#web3-authentication). +You need to create a Clerk application in the [Clerk Dashboard](https://dashboard.clerk.com/) and configure the application to use **Sign in with Metamask**, **Sign in with Coinbase Wallet** or **Sign in with OKX Wallet**. For more information on how to set up a Clerk application, see the [setup guide](/docs/quickstarts/setup-clerk). To enable Metamask, Coinbase Wallet, or OKX Wallet authentication, see the [dedicated guide](/docs/authentication/configuration/sign-up-sign-in-options#web3-authentication). -Ensure that you have downloaded the [Metamask](https://metamask.io/download/) or [Coinbase Wallet](https://www.coinbase.com/wallet/downloads) plugins and installed it on your browser to ensure a seamless sign-in flow. +Ensure that you've installed the [Metamask](https://metamask.io/download/), [Coinbase Wallet](https://www.coinbase.com/wallet/downloads), or [OKX Wallet](https://www.okx.com/help/section/faq-web3-wallet) plugins for a seamless sign-in experience. ## Creating a new Next.js app @@ -17,9 +17,9 @@ Once you have a Clerk application set up in the dashboard, it's time to create a ## Accessing the Web3 address from the frontend -At this point, you should have a Next.js application integrated with Clerk and with Metamask or Coinbase Wallet authentication enabled. Run `npm run dev` and visit `localhost:3000`. If you followed the guide, all of the pages to your application should be protected, and you should see your sign-in page. +At this point, your Next.js application should be integrated with Clerk and configured for authentication using Metamask, Coinbase Wallet, or OKX Wallet. Run `npm run dev` and visit `localhost:3000`. If you followed the guide, all pages in your application will be protected, and you should see your sign-in page. -After signing in with Metamask or Coinbase Wallet, you'll be presented with the Next.js default start screen. Let's modify the start screen to display a user's primary Web3 address on the page. +After signing in with your Web3 provider, you'll be presented with the Next.js default start screen. Let's modify the start screen to display a user's primary Web3 address on the page. In this example, the [`User`](/docs/references/javascript/user/user) object for the current user can be accessed through the [`useUser()`](/docs/references/react/use-user) hook. The user's primary Web3 address can then be retrieved from the `User` object. From ec98265fa798bb0008d78a151400f6e2618704f0 Mon Sep 17 00:00:00 2001 From: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:38:20 -0500 Subject: [PATCH 16/36] (expo) update quickstart to match dashboard (#1788) --- docs/quickstarts/expo.mdx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/quickstarts/expo.mdx b/docs/quickstarts/expo.mdx index 08b1465e5e..572092eba3 100644 --- a/docs/quickstarts/expo.mdx +++ b/docs/quickstarts/expo.mdx @@ -209,7 +209,7 @@ description: Add authentication and user management to your Expo app with Clerk. First, protect your sign-up and sign-in pages. - 1. Create an `(auth)` route group. This will group your sign-up and sign-in pages. + 1. Create an `(auth)` [route group](https://docs.expo.dev/router/layouts/#groups). This will group your sign-up and sign-in pages. 1. In the `(auth)` group, create a `_layout.tsx` file. 1. Paste the following code. The [`useAuth()`](/docs/references/react/use-auth) hook is used to access the user's authentication state. If the user is already signed in, they will be redirected to the home page. @@ -410,14 +410,18 @@ description: Add authentication and user management to your Expo app with Clerk. For more information about building these custom flows, including guided comments in the code examples, see the [Build a custom email/password authentication flow](/docs/custom-flows/email-password) guide. - ### Protect your pages + ### Conditionally render content You can control which content signed-in and signed-out users can see with Clerk's [prebuilt control components](/docs/components/overview#what-are-control-components). For this quickstart, you'll use: - [``](/docs/components/control/signed-in): Children of this component can only be seen while **signed in**. - [``](/docs/components/control/signed-out): Children of this component can only be seen while **signed out**. - To get started, create a `(home)` [route group](https://docs.expo.dev/router/layouts/#groups) with the following layout file: + To get started: + + 1. Create a `(home)` route group. + 1. In the `(home)` group, create a `_layout.tsx` file. + 1. Paste the following code. ```tsx filename="app/(home)/_layout.tsx" import { Stack } from 'expo-router/stack' @@ -427,7 +431,7 @@ description: Add authentication and user management to your Expo app with Clerk. } ``` - Then, in the same folder, create an `index.tsx` file and add the following code. It displays the user's email if they're signed in, or sign-in and sign-up links if they're not: + Then, in the same folder, create an `index.tsx` file with the following code. It displays the user's email if they're signed in, or sign-in and sign-up links if they're not: ```tsx filename="app/(home)/index.tsx" import { SignedIn, SignedOut, useUser } from '@clerk/clerk-expo' From f3b88b2c5ff04de8ec4c3d62abc3ff3ada614651 Mon Sep 17 00:00:00 2001 From: Mary Zhong Date: Tue, 10 Dec 2024 12:32:51 -0500 Subject: [PATCH 17/36] fix: Remove snipped about xms_edov being in preview (#1786) --- .../authentication/enterprise-connections/easie/microsoft.mdx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/authentication/enterprise-connections/easie/microsoft.mdx b/docs/authentication/enterprise-connections/easie/microsoft.mdx index 026abb0cf8..f0ac052697 100644 --- a/docs/authentication/enterprise-connections/easie/microsoft.mdx +++ b/docs/authentication/enterprise-connections/easie/microsoft.mdx @@ -74,7 +74,7 @@ To make the setup process easier, it's recommended to keep two browser tabs open [nOAuth](https://www.descope.com/blog/post/noauth) is an exploit in Microsoft Entra ID OAuth apps that can lead to account takeovers via email address spoofing. Clerk mitigates this risk by enforcing stricter checks on verified email addresses. - For further security, Microsoft offers an optional `xms_edov` claim, which provides additional context to determine whether the returned email is verified. + For further security, Microsoft offers an optional `xms_edov` [claim](https://learn.microsoft.com/en-us/entra/identity-platform/optional-claims-reference), which provides additional context to determine whether the returned email is verified. This claim is mandatory for applications backing EASIE connections. To enable it, you must: @@ -83,8 +83,6 @@ To make the setup process easier, it's recommended to keep two browser tabs open 1. Select **Add optional claim**. 1. For the **Token type**, select **ID**. Then, in the table that opens, enable the `email` and `xms_pdl` claims. 1. At the bottom of the modal, select **Add**. A new modal will prompt you to turn on the Microsoft Graph email permission. Enable it, then select **Add** to complete the form. - > [!NOTE] - > At the time of writing, the `xms_edov` claim is still in preview and may not be available for all apps. We'll choose another claim and rename it in the manifest later. 1. Repeat the previous steps for **Token type**, but select **Access** instead of **ID**. The **Optional claims** list should now show two claims for `email` and two for `xms_pdl`: one each for **ID** and **Access**. 1. In the sidebar, go to **Manifest**. 1. In the text editor, search for `"acceptMappedClaims"` and set its value from `null` to `true`. From ff3c2242ff438b624a54185d93acdeeb4cd571c3 Mon Sep 17 00:00:00 2001 From: Zach Shilton <4624598+zchsh@users.noreply.github.com> Date: Tue, 10 Dec 2024 12:41:56 -0500 Subject: [PATCH 18/36] fix: typo in custom-session-token docs (#1787) --- .../backend-requests/making/custom-session-token.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/backend-requests/making/custom-session-token.mdx b/docs/backend-requests/making/custom-session-token.mdx index 6a15fed211..ee28e7e925 100644 --- a/docs/backend-requests/making/custom-session-token.mdx +++ b/docs/backend-requests/making/custom-session-token.mdx @@ -40,11 +40,11 @@ This guide will show you how to customize a session token to include additional export default async function Page() { const { sessionClaims } = await auth() - const firstName = sessionClaims?.fullName + const fullName = sessionClaims?.fullName const primaryEmail = sessionClaims?.primaryEmail - return NextResponse.json({ firstName, primaryEmail }) + return NextResponse.json({ fullName, primaryEmail }) } ``` @@ -55,11 +55,11 @@ This guide will show you how to customize a session token to include additional export default async function handler(req: NextApiRequest, res: NextApiResponse) { const { sessionClaims } = getAuth(req) - const firstName = sessionClaims.fullName + const fullName = sessionClaims.fullName const primaryEmail = sessionClaims.primaryEmail - return res.status(200).json({ firstName, primaryEmail }) + return res.status(200).json({ fullName, primaryEmail }) } ``` @@ -73,14 +73,14 @@ This guide will show you how to customize a session token to include additional 1. Create the `CustomJwtSessionClaims` interface and declare it globally. 1. Add the custom claims to the `CustomJwtSessionClaims` interface. - The following example demonstrates how to add the `firstName` and `primaryEmail` claims to the `CustomJwtSessionClaims` interface. + The following example demonstrates how to add the `fullName` and `primaryEmail` claims to the `CustomJwtSessionClaims` interface. ```tsx {{ filename: 'types/globals.d.ts' }} export {} declare global { interface CustomJwtSessionClaims { - firstName?: string + fullName?: string primaryEmail?: string } } From 0b622492ff7e0bc6a388d3be12c03165efe9fce7 Mon Sep 17 00:00:00 2001 From: Jakob Evangelista <79593812+jakobevangelista@users.noreply.github.com> Date: Tue, 10 Dec 2024 09:42:15 -0800 Subject: [PATCH 19/36] feat: Add Force MFA Example (#1723) Co-authored-by: Jacek Co-authored-by: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> --- docs/custom-flows/manage-totp-based-mfa.mdx | 48 +++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/docs/custom-flows/manage-totp-based-mfa.mdx b/docs/custom-flows/manage-totp-based-mfa.mdx index 62acebef61..62fee0ab1a 100644 --- a/docs/custom-flows/manage-totp-based-mfa.mdx +++ b/docs/custom-flows/manage-totp-based-mfa.mdx @@ -305,6 +305,54 @@ One of the options that Clerk supports for MFA is **Authenticator applications ( ``` + + #### Force MFA (optional) + + While Clerk does not natively enforce MFA for all users, you can implement this functionality by using `clerkMiddleware()` to check whether a user has MFA enabled. + + The following example demonstrates how to force MFA for all users. It uses `clerkMiddleware()` to intercept all requests and check whether a user has MFA enabled. If the user does not have MFA enabled, `clerkMiddleware()` redirects them to the `/mfa` page where they can set up MFA. + + ```tsx {{ filename: 'middleware.ts', collapsible: true }} + import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server' + import { NextResponse } from 'next/server' + + const isMFARoute = createRouteMatcher(['/account/manage-mfa/add(.*)']) + const isSignInRoute = createRouteMatcher(['/sign-in(.*)']) + + export default clerkMiddleware(async (auth, req) => { + const { userId } = await auth() + + // Redirect to homepage if the user is signed in and on the sign-in page + if (userId !== null && isSignInRoute(req) && !isMFARoute(req)) { + return NextResponse.redirect(new URL('/', req.url)) + } + + // Check if the user is signed in and not on the MFA page + if (userId !== null && !isMFARoute(req)) { + const res = await fetch(`https://api.clerk.com/v1/users/${userId}`, { + headers: { + Authorization: `Bearer ${process.env.CLERK_SECRET_KEY}`, + }, + }) + + const userData = await res.json() + + // Redirect to MFA setup page if MFA is not enabled + if (userData.two_factor_enabled === false) { + return NextResponse.redirect(new URL('/account/manage-mfa/add', req.url)) + } + } + }) + + export const config = { + matcher: [ + // Skip Next.js internals and all static files, unless found in search params + '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)', + // Always run for API routes + '/(api|trpc)(.*)', + ], + } + ``` From 1c92a55beb25da0f954b184217b17172482bac74 Mon Sep 17 00:00:00 2001 From: victoria Date: Tue, 10 Dec 2024 12:58:03 -0500 Subject: [PATCH 20/36] chore: update page titles to "Clerk _Name_ SDK" for sdk reference overviews (#1789) Co-authored-by: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> --- docs/references/astro/overview.mdx | 2 +- docs/references/chrome-extension/overview.mdx | 4 ++-- docs/references/expo/overview.mdx | 2 +- docs/references/javascript/overview.mdx | 4 ++-- docs/references/nextjs/overview.mdx | 2 +- docs/references/redwood/overview.mdx | 2 +- docs/references/tanstack-start/overview.mdx | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/references/astro/overview.mdx b/docs/references/astro/overview.mdx index 02c00f4563..559c351041 100644 --- a/docs/references/astro/overview.mdx +++ b/docs/references/astro/overview.mdx @@ -1,5 +1,5 @@ --- -title: Astro and Clerk +title: Clerk Astro SDK description: Learn how to use Clerk to quickly and easily add secure authentication and user management to your Astro application. --- diff --git a/docs/references/chrome-extension/overview.mdx b/docs/references/chrome-extension/overview.mdx index df84258fed..2f2ba6ffd8 100644 --- a/docs/references/chrome-extension/overview.mdx +++ b/docs/references/chrome-extension/overview.mdx @@ -1,6 +1,6 @@ --- -title: Chrome Extension SDK -description: Learn how to integrate Clerk into your Chrome Extension +title: Clerk Chrome Extension SDK +description: Learn how to use Clerk to quickly and easily add secure authentication and user management to your Chrome Extension. --- Clerk provides a Chrome Extension SDK that allows you to easily integrate Clerk into your Chrome Extension. This SDK provides a simple way to authenticate users and manage their sessions. diff --git a/docs/references/expo/overview.mdx b/docs/references/expo/overview.mdx index bf8578c3fd..8afb14999e 100644 --- a/docs/references/expo/overview.mdx +++ b/docs/references/expo/overview.mdx @@ -1,5 +1,5 @@ --- -title: Expo and Clerk +title: Clerk Expo SDK description: Learn how to use Clerk to quickly and easily add secure authentication and user management to your Expo application. --- diff --git a/docs/references/javascript/overview.mdx b/docs/references/javascript/overview.mdx index 55031d0fdf..289ee7529c 100644 --- a/docs/references/javascript/overview.mdx +++ b/docs/references/javascript/overview.mdx @@ -1,6 +1,6 @@ --- -title: ClerkJS -description: ClerkJS is Clerk's foundational JavaScript library for building user management and authentication. +title: Clerk JavaScript SDK +description: Clerk's JavaScript SDK is a foundational library for building user management and authentication. --- ClerkJS is our foundational JavaScript library for building user management and authentication. It enables you to register, sign in, verify and manage users for your application using highly customizable flows. diff --git a/docs/references/nextjs/overview.mdx b/docs/references/nextjs/overview.mdx index f48eac6e73..0dd5f02bd3 100644 --- a/docs/references/nextjs/overview.mdx +++ b/docs/references/nextjs/overview.mdx @@ -1,5 +1,5 @@ --- -title: Next.js reference overview +title: Clerk Next.js SDK description: Learn how to use Clerk to quickly and easily add secure authentication and user management to your Next.js application. --- diff --git a/docs/references/redwood/overview.mdx b/docs/references/redwood/overview.mdx index 938bd3f4b0..02fcd94e68 100644 --- a/docs/references/redwood/overview.mdx +++ b/docs/references/redwood/overview.mdx @@ -1,5 +1,5 @@ --- -title: Use Clerk with RedwoodJS +title: Clerk RedwoodJS SDK description: Learn how to use Clerk to quickly and easily add secure authentication and user management to your RedwoodJS application. --- diff --git a/docs/references/tanstack-start/overview.mdx b/docs/references/tanstack-start/overview.mdx index 59c1d555ca..68a1d12288 100644 --- a/docs/references/tanstack-start/overview.mdx +++ b/docs/references/tanstack-start/overview.mdx @@ -1,5 +1,5 @@ --- -title: "TanStack Start and Clerk" +title: Clerk TanStack Start SDK description: Learn how to use Clerk to quickly and easily add secure authentication and user management to your TanStack Start application. --- From f34168acab5b97a5a8f52f9d82b2f02afecca6bd Mon Sep 17 00:00:00 2001 From: Nikos Polykandriotis Date: Wed, 11 Dec 2024 10:51:59 +0200 Subject: [PATCH 21/36] feat: Add docs for third party OIDC providers (#1769) Co-authored-by: victoria Co-authored-by: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> --- .../oidc/custom-provider.mdx | 88 +++++++++++++++++++ .../enterprise-connections/overview.mdx | 16 ++-- docs/manifest.json | 11 +++ 3 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 docs/authentication/enterprise-connections/oidc/custom-provider.mdx diff --git a/docs/authentication/enterprise-connections/oidc/custom-provider.mdx b/docs/authentication/enterprise-connections/oidc/custom-provider.mdx new file mode 100644 index 0000000000..3ae5b0ce3f --- /dev/null +++ b/docs/authentication/enterprise-connections/oidc/custom-provider.mdx @@ -0,0 +1,88 @@ +--- +title: Add a custom OpenID Connect (OIDC) Provider as an enterprise connection +description: Learn how to integrate a custom OIDC provider with Clerk for Enterprise SSO. +--- + + + - Add a custom OIDC provider to authenticate users with Enterprise SSO + + +This guide explains how to use a custom [OpenID Connect (OIDC)](https://openid.net/developers/how-connect-works) provider to authenticate users via Enterprise SSO. + +To make the setup process easier, it's recommended to keep two browser tabs open: one for the [Clerk Dashboard](https://dashboard.clerk.com/last-active?path=user-authentication/sso-connections) and one for your Identity Provider (IdP). + + + ### Set up an enterprise connection in Clerk + + 1. In the Clerk Dashboard, navigate to the [**SSO Connections**](https://dashboard.clerk.com/last-active?path=user-authentication/sso-connections) page. + 1. Select **Add connection** and select **For specific domains**. + 1. Under **Third party**, select **OpenID Connect (OIDC)**. + 1. Add the **Name** of the connection. + 1. Add the **Key** of the provider. This is the provider's unique identifier (cannot be changed after creation). + 1. Add the **Specific Domain** that you want to allow this connection for. This is the domain of the users you want to allow to sign in to your app. + 1. Select **Add connection**. You will be redirected to the connection's configuration page. Keep this page open. + + ### Configure your IdP + + 1. If necessary, create a new application in your IdP. + 1. In the connection's configuration page of the Clerk Dashboard, copy the **Authorized redirect URI**. + 1. Add the value to your IdP's whitelisted URLs. + 1. Find your application's **Discovery Endpoint**, **Client ID**, and **Client Secret** and copy them. + + ### Set the Discovery Endpoint, Client ID, and Client Secret in Clerk + + 1. In your IdP settings, copy your application's **Discovery Endpoint**, **Client ID**, and **Client Secret**. + 1. In the connection's configuration page in the Clerk Dashboard, paste these values in their respective fields. + 1. Under **Scopes**, add the minimum required scopes based on the IdP's documentation if needed. Common OIDC scopes include `openid`, `email`, and `profile`. + 1. Select **Save**. + + > [!NOTE] + > Most IdPs provide a **Discovery Endpoint** to retrieve metadata about an OIDC provider. If your IdP doesn't offer this endpoint or if you need greater control over the setup process, in the connection's configuration page in the Clerk Dashboard, find the **Identity Provider Configuration** section and select **Use Manual Configuration** to manually configure the connection. + + ### Configure attribute mapping (optional) + + Clerk expects the claims returned by your IdP to follow the [OIDC Standard](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims). If your provider returns claims in a non-standard format, use the **Attribute Mapping** section on the connection's configuration page to adjust the mapping of Clerk's user properties to match the IdP's claim attributes. + + > [!WARNING] + > OIDC Enterprise connections require the [`email_verified`](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims:~:text=Section%C2%A05.7.-,email_verified,-boolean) claim to verify email ownership. However, some IdPs, such as Microsoft Azure Active Directory, might not return this claim or use a non-standard format. + > + > If the IdP doesn't return this claim, you can leave the **Email address verified** field blank and set the **Default value** to **True**. This should only be done if you fully trust the IdP, as it can expose your app to [OAuth attacks](https://www.descope.com/blog/post/noauth). + + ### Allow additional identifiers (optional) + + User profile information is sourced from the IdP. To allow users to add new identifiers (e.g., email address or phone number) to their profiles: + + 1. In the connection's configuration page of the Clerk Dashboard, navigate to the **Advanced** tab. + 1. Enable **Allow additional identifiers**. + 1. Select **Save**. + + ### Enable the connection for Clerk + + To make the connection available for your users to authenticate with: + + 1. Navigate back to the Clerk Dashboard where you should still have the connection's configuration page open. If not, navigate to the [**SSO connections**](https://dashboard.clerk.com/last-active?path=user-authentication/sso-connections) page and select the connection. + 1. At the top of the page, toggle on **Enable connection** and select **Save**. + + ### Test your connection + + The simplest way to test your enterprise connection is to visit your Clerk app's [Account Portal](/docs/customization/account-portal/overview), which is available for all Clerk apps out-of-the-box. + + 1. In the Clerk Dashboard, navigate to the [**Account Portal**](https://dashboard.clerk.com/last-active?path=account-portal) page. + 1. Next to the **Sign-in** URL, select **Visit**. The URL should resemble: + - **For development** – `https://your-domain.accounts.dev/sign-in` + - **For production** – `https://accounts.your-domain.com/sign-in` + 1. Sign in with your IdP account. + diff --git a/docs/authentication/enterprise-connections/overview.mdx b/docs/authentication/enterprise-connections/overview.mdx index 6961a7c90f..5a8df7cb68 100644 --- a/docs/authentication/enterprise-connections/overview.mdx +++ b/docs/authentication/enterprise-connections/overview.mdx @@ -1,15 +1,15 @@ --- -title: Enterprise SSO +title: Enterprise Single Sign-On (SSO) description: Clerk provides Enterprise SSO to authenticate users via federated Identity Providers such such as Azure AD, Okta, Google Workspace and more. --- -With Enterprise SSO, users can sign in seamlessly using their Identity Provider's (IdP) credentials and have their user data synchronized with Clerk. You can learn more about the process in the guides on [authentication flows](/docs/authentication/enterprise-connections/authentication-flows) and [account linking](/docs/authentication/enterprise-connections/account-linking). +Enterprise Single Sign-On (SSO) allows users to sign in seamlessly using their Identity Provider (IdP) credentials (e.g.,Azure AD, Okta, or Google Workspace) and have their user data synchronized with Clerk. Clerk supports multiple protocols for implementing Enterprise SSO, including SAML and OIDC. Learn more about the process in the guides on [authentication flows](/docs/authentication/enterprise-connections/authentication-flows) and [account linking](/docs/authentication/enterprise-connections/account-linking). ## SAML Clerk supports Enterprise SSO via the SAML protocol, enabling you to create authentication strategies for an IdP. The following IdPs are supported: [Microsoft Azure AD](/docs/authentication/enterprise-connections/saml/azure), [Google Workspace](/docs/authentication/enterprise-connections/saml/google), and [Okta Workforce](/docs/authentication/enterprise-connections/saml/okta). However, you can also [integrate with any other IdP](/docs/authentication/enterprise-connections/saml/custom-provider) that supports the SAML protocol. -### Allow subdomains +#### Allow subdomains Authenticating via SAML SSO requires the user's email address domain to match the exact domain the SAML connection has been configured with. By default, subdomains are not supported. For example, a user with the email address `john@sales.example.com` wouldn't be able to use a SAML connection with the `example.com` domain to authenticate. @@ -24,7 +24,11 @@ To configure subdomains for a SAML connection: > [!NOTE] > To enable the **Allow subdomains** option, your SAML connection domain must be an [eTLD+1](https://developer.mozilla.org/en-US/docs/Glossary/eTLD). -## EASIE +## OIDC + +Clerk supports Enterprise SSO via the OpenID Connect (OIDC) protocol, either through [EASIE](#easie) or by [integrating with any OIDC-compatible provider](/docs/authentication/enterprise-connections/oidc/custom-provider). + +### EASIE [EASIE](https://easie.dev) SSO is a way for applications to provide enterprise-grade SSO through a multi-tenant OpenID provider. It is designed to be an easier alternative to SAML SSO. @@ -33,7 +37,7 @@ The following IdPs are supported: Google Workspace and Microsoft Entra ID. For _ - [Google](/docs/authentication/social-connections/google) - [Microsoft](/docs/authentication/social-connections/microsoft) -### Automatic deprovisioning +#### Automatic deprovisioning Clerk prevents users linked to deprovisioned accounts in the OpenID provider from accessing the app. @@ -41,7 +45,7 @@ Within 10 minutes of a user being removed from the OpenID provider (e.g. [suspen It is ultimately the app's responsibility to handle this unauthenticated state and display something appropriate to the user. For example, Next.js apps using [`auth.protect()`](/docs/references/nextjs/auth#auth-protect) will automatically redirect the user to the sign-in page. -## SAML vs. EASIE +### SAML vs. EASIE The primary security difference between EASIE SSO and SAML SSO is that EASIE depends on a multi-tenant identity provider, while SAML depends on a single-tenant identity provider. Relying on a multi-tenant provider **increases** the risk that a user from one tenant will mistakenly be granted access to the resources of another tenant. While Clerk implements [measures to address this risk](https://easie.dev/#mitigating-tenant-crossover-vulnerabilities), apps that require single-tenant IdPs should opt for SAML. diff --git a/docs/manifest.json b/docs/manifest.json index 7f84702730..0e1a92425b 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -579,6 +579,17 @@ } ] ] + }, + { + "title": "OIDC", + "items": [ + [ + { + "title": "Custom provider", + "href": "/docs/authentication/enterprise-connections/oidc/custom-provider" + } + ] + ] } ] ] From 7177bf37d8e46e694dcfdab3f1a06ad32778dc96 Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Wed, 11 Dec 2024 15:37:38 -0600 Subject: [PATCH 22/36] feat: Add allowedRedirectProtocols documentation (#1767) --- docs/components/clerk-provider.mdx | 9 ++++++++- docs/references/javascript/clerk/clerk.mdx | 13 ++++++++++--- docs/references/remix/clerk-app.mdx | 9 ++++++++- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/docs/components/clerk-provider.mdx b/docs/components/clerk-provider.mdx index 676a3bb84e..ce49730c31 100644 --- a/docs/components/clerk-provider.mdx +++ b/docs/components/clerk-provider.mdx @@ -90,7 +90,14 @@ The recommended approach is to wrap your entire app with `` at th - `allowedRedirectOrigins?` - `Array` - Optional array of domains used to validate against the query param of an auth redirect. If no match is made, the redirect is considered unsafe and the default redirect will be used with a warning passed to the console. + An optional array of domains to validate user-provided redirect URLs against. If no match is made, the redirect is considered unsafe and the default redirect will be used with a warning logged in the console. + + --- + + - `allowedRedirectProtocols?` + - `Array` + + An optional array of protocols to validate user-provided redirect URLs against. If no match is made, the redirect is considered unsafe and the default redirect will be used with a warning logged in the console. --- diff --git a/docs/references/javascript/clerk/clerk.mdx b/docs/references/javascript/clerk/clerk.mdx index 57522e3841..a576657395 100644 --- a/docs/references/javascript/clerk/clerk.mdx +++ b/docs/references/javascript/clerk/clerk.mdx @@ -457,10 +457,17 @@ All props below are optional. --- - - `allowedRedirectOrigins` - - `Array | undefined` + - `allowedRedirectOrigins?` + - `Array` - Optional array of domains used to validate against the query param of an auth redirect.
If no match is made, the redirect is considered unsafe and the default redirect will be used with a warning passed to the console. + An optional array of domains to validate user-provided redirect URLs against. If no match is made, the redirect is considered unsafe and the default redirect will be used with a warning logged in the console. + + --- + + - `allowedRedirectProtocols?` + - `Array` + + An optional array of protocols to validate user-provided redirect URLs against. If no match is made, the redirect is considered unsafe and the default redirect will be used with a warning logged in the console. --- diff --git a/docs/references/remix/clerk-app.mdx b/docs/references/remix/clerk-app.mdx index d165a65a56..c1070fc202 100644 --- a/docs/references/remix/clerk-app.mdx +++ b/docs/references/remix/clerk-app.mdx @@ -80,7 +80,14 @@ export default ClerkApp(App) - `allowedRedirectOrigins?` - `Array` - Optional array of domains used to validate against the query param of an auth redirect. If no match is made, the redirect is considered unsafe and the default redirect will be used with a warning passed to the console. + An optional array of domains to validate user-provided redirect URLs against. If no match is made, the redirect is considered unsafe and the default redirect will be used with a warning logged in the console. + + --- + + - `allowedRedirectProtocols?` + - `Array` + + An optional array of protocols to validate user-provided redirect URLs against. If no match is made, the redirect is considered unsafe and the default redirect will be used with a warning logged in the console. [components-ref]: /docs/components/overview From 7df533daf7aae60919592d285ce75f6bd402504d Mon Sep 17 00:00:00 2001 From: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> Date: Wed, 11 Dec 2024 17:13:29 -0500 Subject: [PATCH 23/36] (chore) add missing expo useoauth hook to sidenav (#1797) Co-authored-by: victoria --- docs/manifest.json | 31 +++++++++++++------ .../references/expo/use-local-credentials.mdx | 1 + docs/references/expo/use-oauth.mdx | 2 +- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/docs/manifest.json b/docs/manifest.json index 0e1a92425b..351643127d 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -2293,21 +2293,16 @@ "href": "/docs/references/expo/overview" }, { - "title": "useLocalCredentials()", - "href": "/docs/references/expo/use-local-credentials" - }, - { - "title": "Web support", - "collapse": true, + "title": "Hooks", "items": [ [ { - "title": "Overview", - "href": "/docs/references/expo/web-support/overview" + "title": "useLocalCredentials()", + "href": "/docs/references/expo/use-local-credentials" }, { - "title": "Add custom sign-up and sign-in pages", - "href": "/docs/references/expo/web-support/custom-signup-signin-pages" + "title": "useOAuth()", + "href": "/docs/references/expo/use-oauth" } ] ] @@ -2326,6 +2321,22 @@ } ] ] + }, + { + "title": "Web support", + "collapse": true, + "items": [ + [ + { + "title": "Overview", + "href": "/docs/references/expo/web-support/overview" + }, + { + "title": "Add custom sign-up and sign-in pages", + "href": "/docs/references/expo/web-support/custom-signup-signin-pages" + } + ] + ] } ] ] diff --git a/docs/references/expo/use-local-credentials.mdx b/docs/references/expo/use-local-credentials.mdx index 77286541fc..f08349cd38 100644 --- a/docs/references/expo/use-local-credentials.mdx +++ b/docs/references/expo/use-local-credentials.mdx @@ -6,6 +6,7 @@ description: Clerk's useLocalCredentials() hook enables you to store and access The `useLocalCredentials()` hook enables you to store a user's password credentials on their device and subsequently use biometrics for sign-in. This enhances the user experience by allowing users to sign in using Face ID or another biometric authentication method during future sign-ins. > [!WARNING] +> This hook isn't supported in web apps and can only be used in native apps. > This API is available only for [@clerk/clerk-expo v2](/docs/upgrade-guides/expo-v2/upgrade) >=2.2.0. > Be aware that this works only for sign-in attempts with the [password strategy](/docs/authentication/configuration/sign-up-sign-in-options#authentication-strategies). diff --git a/docs/references/expo/use-oauth.mdx b/docs/references/expo/use-oauth.mdx index 8c686d8c9b..560328433e 100644 --- a/docs/references/expo/use-oauth.mdx +++ b/docs/references/expo/use-oauth.mdx @@ -3,7 +3,7 @@ title: '`useOAuth()`' description: Clerk's useOAuth() hook is used to create a new OAuth flow. --- -The `useOAuth()` hook is used to create a new OAuth flow. +The `useOAuth()` hook is used to create a new OAuth flow. It can be used in both web and native apps. ## Parameters From c9f0793bc56dbed27e3b9455bf2e2b9f5207430c Mon Sep 17 00:00:00 2001 From: Brandon Romano Date: Wed, 11 Dec 2024 14:47:12 -0800 Subject: [PATCH 24/36] Update size limitation docs to reference only session tokens (#1790) --- docs/backend-requests/making/jwt-templates.mdx | 2 -- docs/backend-requests/resources/session-tokens.mdx | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/backend-requests/making/jwt-templates.mdx b/docs/backend-requests/making/jwt-templates.mdx index c07b5f5b1a..96d42f6339 100644 --- a/docs/backend-requests/making/jwt-templates.mdx +++ b/docs/backend-requests/making/jwt-templates.mdx @@ -10,8 +10,6 @@ Clerk offers the ability to generate [JSON Web Tokens](https://en.wikipedia.org/ You can control the claims that will go into these tokens by creating custom **JWT templates** that fit your needs. This enables you to integrate with any third-party services that support authentication with JWTs. An example use case is integrating with a third-party service that is able to consume JWTs, but requires them to be in a particular format. - - ## What is a JWT template? **JWT templates** are essentially JSON objects that specify claims to be included in the generated tokens, along with their respective values. diff --git a/docs/backend-requests/resources/session-tokens.mdx b/docs/backend-requests/resources/session-tokens.mdx index ae43ef8737..ca19a995cb 100644 --- a/docs/backend-requests/resources/session-tokens.mdx +++ b/docs/backend-requests/resources/session-tokens.mdx @@ -38,7 +38,7 @@ You can also create custom tokens using a [JWT template](/docs/backend-requests/ The Clerk session token is stored in a cookie. All modern browsers [limit the maximum size of a cookie to 4kb](https://datatracker.ietf.org/doc/html/rfc2109#section-6.3). Exceeding this limit can have adverse effects, including a possible infinite redirect loop for users who exceed this size in Next.js applications. -A session token with the [default session claims](#default-session-claims) won't run into this issue, as this configuration produces a cookie significantly smaller than 4kb. However, this limitation becomes relevant when implementing a [custom session token](/docs/backend-requests/making/custom-session-token) or creating a [custom JWT template](/docs/backend-requests/making/jwt-templates). In these cases, it's recommended to move particularly large claims out of the token and fetch these using a separate API call from your backend. +A session token with the [default session claims](#default-session-claims) won't run into this issue, as this configuration produces a cookie significantly smaller than 4kb. However, this limitation becomes relevant when implementing a [custom session token](/docs/backend-requests/making/custom-session-token). In this case, it's recommended to move particularly large claims out of the token and fetch these using a separate API call from your backend. Claims to monitor for size limits: @@ -51,7 +51,7 @@ Claims to monitor for size limits: If you include any of these claims in your token, use caution to ensure the stored data doesn't exceed the size limit. > [!NOTE] -> If your application encounters this issue, the Clerk Dashboard will display a warning: **"Some users are exceeding cookie size limits"**. To resolve this, update your [custom session token](/docs/backend-requests/making/custom-session-token) or the [JWT template](/docs/backend-requests/making/jwt-templates) that is referenced in the warning. +> If your application encounters this issue, the Clerk Dashboard will display a warning: **"Some users are exceeding cookie size limits"**. To resolve this, update your [custom session token](/docs/backend-requests/making/custom-session-token). ## Validate session tokens From 40a06c6bfeee6274f6eeb1e76a98cdbe561ebbd2 Mon Sep 17 00:00:00 2001 From: Dylan Staley <88163+dstaley@users.noreply.github.com> Date: Wed, 11 Dec 2024 14:53:09 -0800 Subject: [PATCH 25/36] fix: clarify email address sign up requirements (#1793) Co-authored-by: victoria Co-authored-by: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> --- docs/authentication/configuration/sign-up-sign-in-options.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/authentication/configuration/sign-up-sign-in-options.mdx b/docs/authentication/configuration/sign-up-sign-in-options.mdx index 989bfceca5..4184b85cfe 100644 --- a/docs/authentication/configuration/sign-up-sign-in-options.mdx +++ b/docs/authentication/configuration/sign-up-sign-in-options.mdx @@ -17,7 +17,7 @@ Identifiers are how your application recognizes an individual user. There are th In the application configuration screen, you can select multiple identifiers, but at least one is required. -**Email address** is the most common primary identifier. During the sign-up process, a user must supply and verify their email address. They must keep an email address on their account at all times. However, the email address that was used for registration can be later changed from the user's profile page. +**Email address** is the most common primary identifier. When it is the only enabled identifier, users are required to supply an email address during sign-up and keep one on their account at all times. The email address that was supplied during sign-up can be later changed from the user's profile page. When **phone number** is selected as the identifier, a user can sign up with their phone number and receive a code via SMS to verify it. SMS functionality is restricted to phone numbers from countries enabled on your [SMS allowlist](#sms-allowlist). From 769e60b50c17a13ee1012d9ee04c619a4fc36b7c Mon Sep 17 00:00:00 2001 From: Kevin Wang <26389321+thiskevinwang@users.noreply.github.com> Date: Wed, 11 Dec 2024 17:56:37 -0500 Subject: [PATCH 26/36] chore(testing-tokens): fix signup endpoint (#1795) --- docs/testing/overview.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/testing/overview.mdx b/docs/testing/overview.mdx index e42790ca92..03e99e2955 100644 --- a/docs/testing/overview.mdx +++ b/docs/testing/overview.mdx @@ -21,7 +21,7 @@ Obtained via the [Backend API](/docs/reference/backend-api/tag/Testing-Tokens){{ Once retrieved, include the token value in the `__clerk_testing_token` query parameter in your Frontend API requests. For example, a sign-up request using a Testing Token would look like this: ```shell -POST https://happy-hippo-1.clerk.accounts.dev/v1/sign_ups?__clerk_testing_token=1713877200-c_2J2MvPu9PnXcuhbPZNao0LOXqK9A7YrnBn0HmIWxy +POST https://happy-hippo-1.clerk.accounts.dev/v1/client/sign_ups?__clerk_testing_token=1713877200-c_2J2MvPu9PnXcuhbPZNao0LOXqK9A7YrnBn0HmIWxy ``` For more information, feedback or issues, visit the [`@clerk/testing`](https://github.com/clerk/javascript/tree/main/packages/testing) package. From a34d0fde226c971d21192210b4821aa5c2ae44be Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Thu, 12 Dec 2024 08:29:48 -0600 Subject: [PATCH 27/36] fix(testing): add note about running test setup in serial mode (#1798) --- docs/testing/playwright/overview.mdx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/testing/playwright/overview.mdx b/docs/testing/playwright/overview.mdx index 045c7a409f..db52bdaf37 100644 --- a/docs/testing/playwright/overview.mdx +++ b/docs/testing/playwright/overview.mdx @@ -49,6 +49,9 @@ description: Use Playwright to write end-to-end tests with Clerk. import { clerkSetup } from '@clerk/testing/playwright' import { test as setup } from '@playwright/test' + // Setup must be run serially, this is necessary if Playwright is configured to run fully parallel: https://playwright.dev/docs/test-parallel + setup.describe.configure({ mode: 'serial' }) + setup('global setup', async ({}) => { await clerkSetup() }) From bd1a2b57db73a923b1c4519a7b9c128430088d69 Mon Sep 17 00:00:00 2001 From: Lennart Date: Thu, 12 Dec 2024 16:24:47 +0100 Subject: [PATCH 28/36] feat: Add React Router docs (#1760) Co-authored-by: Brad Cornes Co-authored-by: victoria Co-authored-by: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> --- docs/_partials/react-hooks.mdx | 9 + docs/index.mdx | 6 + docs/manifest.json | 66 +++- docs/manifest.schema.json | 1 + docs/quickstarts/react-router.mdx | 220 ++++++++++++ docs/quickstarts/react.mdx | 7 +- docs/references/nextjs/auth-object.mdx | 4 +- docs/references/nextjs/overview.mdx | 32 +- .../custom-signup-signin-pages.mdx | 91 +++++ docs/references/react-router/get-auth.mdx | 118 +++++++ docs/references/react-router/library-mode.mdx | 128 +++++++ docs/references/react-router/overview.mdx | 33 ++ .../react-router/read-session-data.mdx | 54 +++ .../react-router/root-auth-loader.mdx | 159 +++++++++ docs/references/react/add-react-router.mdx | 334 ------------------ docs/references/react/overview.mdx | 46 ++- .../remix/custom-signup-signin-pages.mdx | 8 +- docs/telemetry.mdx | 12 +- .../create-a-minimal-reproduction.mdx | 2 + 19 files changed, 944 insertions(+), 386 deletions(-) create mode 100644 docs/_partials/react-hooks.mdx create mode 100644 docs/quickstarts/react-router.mdx create mode 100644 docs/references/react-router/custom-signup-signin-pages.mdx create mode 100644 docs/references/react-router/get-auth.mdx create mode 100644 docs/references/react-router/library-mode.mdx create mode 100644 docs/references/react-router/overview.mdx create mode 100644 docs/references/react-router/read-session-data.mdx create mode 100644 docs/references/react-router/root-auth-loader.mdx delete mode 100644 docs/references/react/add-react-router.mdx diff --git a/docs/_partials/react-hooks.mdx b/docs/_partials/react-hooks.mdx new file mode 100644 index 0000000000..594ffdf1e8 --- /dev/null +++ b/docs/_partials/react-hooks.mdx @@ -0,0 +1,9 @@ +- [`useUser()`](/docs/references/react/use-user){{ target: '_blank' }} +- [`useClerk()`](/docs/references/react/use-clerk){{ target: '_blank' }} +- [`useAuth()`](/docs/references/react/use-auth){{ target: '_blank' }} +- [`useSignIn()`](/docs/references/react/use-sign-in){{ target: '_blank' }} +- [`useSignUp()`](/docs/references/react/use-sign-up){{ target: '_blank' }} +- [`useSession()`](/docs/references/react/use-session){{ target: '_blank' }} +- [`useSessionList()`](/docs/references/react/use-session-list){{ target: '_blank' }} +- [`useOrganization()`](/docs/references/react/use-organization){{ target: '_blank' }} +- [`useOrganizationList()`](/docs/references/react/use-organization-list){{ target: '_blank' }} diff --git a/docs/index.mdx b/docs/index.mdx index abd651d85a..554829ae3a 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -78,6 +78,12 @@ Find all the guides and resources you need to develop with Clerk. - [TanStack Start (Beta)](/docs/quickstarts/tanstack-start) - Easily add secure and SSR-friendly authentication to your TanStack Start application with Clerk. - ![](data:image/webp;base64,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) + + --- + + - [React Router (Beta)](/docs/quickstarts/react-router) + - Easily add secure, edge- and SSR-friendly authentication to React Router with Clerk. + - {} ## Explore by backend framework diff --git a/docs/manifest.json b/docs/manifest.json index 351643127d..4b6bc45721 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -30,6 +30,12 @@ "href": "/docs/quickstarts/nextjs", "icon": "nextjs" }, + { + "title": "React Router", + "tag": "(Beta)", + "href": "/docs/quickstarts/react-router", + "icon": "react-router" + }, { "title": "Remix", "href": "/docs/quickstarts/remix", @@ -1872,17 +1878,6 @@ "title": "Overview", "href": "/docs/references/react/overview" }, - { - "title": "Guides", - "items": [ - [ - { - "title": "Add React Router", - "href": "/docs/references/react/add-react-router" - } - ] - ] - }, { "title": "Client-side Helpers", "items": [ @@ -2404,6 +2399,55 @@ ] ] }, + { + "title": "React Router", + "collapse": true, + "icon": "react-router", + "tag": "(Beta)", + "items": [ + [ + { + "title": "Overview", + "href": "/docs/references/react-router/overview" + }, + { + "title": "Guides", + "items": [ + [ + { + "title": "Read session and user data", + "href": "/docs/references/react-router/read-session-data" + }, + { + "title": "Add custom sign up and sign in pages", + "href": "/docs/references/react-router/custom-signup-signin-pages" + }, + { + "title": "Library mode", + "href": "/docs/references/react-router/library-mode" + } + ] + ] + }, + { + "title": "General References", + "items": [ + [ + { + "title": "`rootAuthLoader()`", + "wrap": false, + "href": "/docs/references/react-router/root-auth-loader" + }, + { + "title": "`getAuth()`", + "href": "/docs/references/react-router/get-auth" + } + ] + ] + } + ] + ] + }, { "title": "Remix", "collapse": true, diff --git a/docs/manifest.schema.json b/docs/manifest.schema.json index dce30cb164..d2e07cba0d 100644 --- a/docs/manifest.schema.json +++ b/docs/manifest.schema.json @@ -125,6 +125,7 @@ "react", "redwood", "remix", + "react-router", "rocket", "route", "ruby", diff --git a/docs/quickstarts/react-router.mdx b/docs/quickstarts/react-router.mdx new file mode 100644 index 0000000000..cdaab7e726 --- /dev/null +++ b/docs/quickstarts/react-router.mdx @@ -0,0 +1,220 @@ +--- +title: React Router Quickstart (Beta) +description: Learn how to use Clerk to quickly and easily add secure authentication and user management to your React Router application. +--- + + + - Install `@clerk/react-router` + - Set your Clerk API keys + - Configure `rootAuthLoader()` + - Add `` and Clerk components + + +Clerk's [React Router SDK](/docs/references/react-router/overview) provides prebuilt components, hooks, and stores to make it easy to integrate authentication and user management in your React Router app. This guide assumes that you're using [React Router v7 or later](https://api.reactrouter.com/v7). + + + ### Install `@clerk/react-router` + + Run the following command to install the SDK: + + + ```bash {{ filename: 'terminal' }} + npm install @clerk/react-router + ``` + + ```bash {{ filename: 'terminal' }} + yarn add @clerk/react-router + ``` + + ```bash {{ filename: 'terminal' }} + pnpm add @clerk/react-router + ``` + + + ### Set your Clerk API keys + + + Add the following keys to your `.env` file. These keys can always be retrieved from the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page in the Clerk Dashboard. + + + + 1. In the Clerk Dashboard, navigate to the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page. + 1. In the **Quick Copy** section, copy your Clerk Publishable and Secret Key. + 1. Paste your keys into your `.env` file. + + The final result should resemble the following: + + + ```env {{ filename: '.env' }} + VITE_CLERK_PUBLISHABLE_KEY={{pub_key}} + CLERK_SECRET_KEY={{secret}} + ``` + + ### Configure `rootAuthLoader()` + + The `rootAuthLoader()` function provides access to authentication state in any React Router route. + + The following code shows how to add this function to your `root.tsx` file. If you're using [Clerk's React Router quickstart](https://github.com/clerk/clerk-react-router-quickstart) or the [React Router template](https://reactrouter.com/start/framework/installation), most of this code will already be present. + + To load additional data or configure options, see the [`rootAuthLoader()`](/docs/references/react-router/root-auth-loader) reference. + + ```tsx {{ filename: 'app/root.tsx', mark: [1, [6, 8]], collapsible: true }} + import { rootAuthLoader } from '@clerk/react-router/ssr.server' + import { isRouteErrorResponse, Links, Meta, Outlet, Scripts, ScrollRestoration } from 'react-router' + import type { Route } from './+types/root' + import stylesheet from './app.css?url' + + export async function loader(args: Route.LoaderArgs) { + return rootAuthLoader(args) + } + + export const links: Route.LinksFunction = () => [ + { rel: 'preconnect', href: 'https://fonts.googleapis.com' }, + { + rel: 'preconnect', + href: 'https://fonts.gstatic.com', + crossOrigin: 'anonymous', + }, + { + rel: 'stylesheet', + href: 'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap', + }, + { rel: 'stylesheet', href: stylesheet }, + ] + + export function Layout({ children }: { children: React.ReactNode }) { + return ( + + + + + + + + + {children} + + + + + ) + } + + export default function App() { + return + } + + export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) { + let message = 'Oops!' + let details = 'An unexpected error occurred.' + let stack: string | undefined + + if (isRouteErrorResponse(error)) { + message = error.status === 404 ? '404' : 'Error' + details = + error.status === 404 ? 'The requested page could not be found.' : error.statusText || details + } else if (import.meta.env.DEV && error && error instanceof Error) { + details = error.message + stack = error.stack + } + + return ( +
+

{message}

+

{details}

+ {stack && ( +
+            {stack}
+          
+ )} +
+ ) + } + ``` + + ### Add `` and Clerk components to your app + + + + It's required to pass `loaderData` to the `` component. This data is provided by the `rootAuthLoader()` function. It's also recommended to pass the `signUpFallbackRedirectUrl` and `signInFallbackRedirectUrl` props. These specify the fallback URL to redirect to after the user signs up or signs in, respectively, if there's no `redirect_url` in the path already. + + You can control which content signed-in and signed-out users can see with Clerk's [prebuilt control components](/docs/components/overview#what-are-control-components). + + The following example adds `` and creates a header using the following Clerk components: + + - [``](/docs/components/control/signed-in): Children of this component can only be seen while **signed in**. + - [``](/docs/components/control/signed-out): Children of this component can only be seen while **signed out**. + - [``](/docs/components/user/user-button): Shows the signed-in user's avatar. Selecting it opens a dropdown menu with account management options. + - [``](/docs/components/unstyled/sign-in-button): An unstyled component that links to the sign-in page. In this example, since no props or [environment variables](/docs/deployments/clerk-environment-variables) are set for the sign-in URL, this component links to the [Account Portal sign-in page](/docs/customization/account-portal/overview#sign-in). + + ```tsx {{ filename: 'app/root.tsx' }} + // Other imports + + import { ClerkProvider, SignedIn, SignedOut, UserButton, SignInButton } from '@clerk/react-router' + + export default function App({ loaderData }: Route.ComponentProps) { + return ( + +
+ + + + + + +
+
+ +
+
+ ) + } + + // Rest of the root.tsx code + ``` + + ### Create your first user + + Run your project with the following command: + + + ```bash {{ filename: 'terminal' }} + npm run dev + ``` + + ```bash {{ filename: 'terminal' }} + yarn dev + ``` + + ```bash {{ filename: 'terminal' }} + pnpm dev + ``` + + + Visit your app's homepage at [`http://localhost:5173`](http://localhost:5173). Sign up to create your first user. +
diff --git a/docs/quickstarts/react.mdx b/docs/quickstarts/react.mdx index 9951acbcd9..21ba2e4f7f 100644 --- a/docs/quickstarts/react.mdx +++ b/docs/quickstarts/react.mdx @@ -148,7 +148,7 @@ description: Add authentication and user management to your React app with Clerk ### Create a header with Clerk components - You can control which content signed-in and signed-out users can see with the [prebuilt control components](/docs/components/overview#what-are-control-components). Create a header using the following components: + You can control which content signed-in and signed-out users can see with the [prebuilt control components](/docs/components/overview#what-are-control-components). The following example creates a header using the following components: - [``](/docs/components/control/signed-in): Children of this component can only be seen while **signed in**. - [``](/docs/components/control/signed-out): Children of this component can only be seen while **signed out**. @@ -195,7 +195,10 @@ description: Add authentication and user management to your React app with Clerk ## Next step: Add routing with React Router -React has many options for handling routing, and you are free to choose the option that suits you best. If you would like to learn how to integrate React Router's latest Data API-based router (also known as Data Router), see the [dedicated guide](/docs/references/react/add-react-router). +React Router can be integrated with Clerk in two ways: + +- As a framework: Use Clerk's built-in [React Router integration](/docs/quickstarts/react-router) +- As a library: Manually integrate React Router into your Clerk application using [library mode](/docs/references/react-router/library-mode) ## More resources diff --git a/docs/references/nextjs/auth-object.mdx b/docs/references/nextjs/auth-object.mdx index d32ad7e978..7ccbab87e2 100644 --- a/docs/references/nextjs/auth-object.mdx +++ b/docs/references/nextjs/auth-object.mdx @@ -1,9 +1,9 @@ --- -title: '`Auth` object' +title: Auth object description: The Auth object contains information about the current user's session. --- -The `Auth` object contains important information like the current user's session ID, user ID, and organization ID. It also contains methods to check for permissions and retrieve the current user's session token. It's returned by the [`useAuth()`](/docs/references/react/use-auth) hook, the [`auth()`](/docs/references/nextjs/auth) and [`getAuth()`](/docs/references/nextjs/get-auth) helpers, and the `request` object in server contexts. +The `Auth` object contains important information like the current user's session ID, user ID, and organization ID. It also contains methods to check for permissions and retrieve the current user's session token. It's returned by the [`useAuth()`](/docs/references/react/use-auth) hook, the [`auth()`](/docs/references/nextjs/auth) and `getAuth()` helpers, and the `request` object in server contexts. ## `Auth` object properties diff --git a/docs/references/nextjs/overview.mdx b/docs/references/nextjs/overview.mdx index 0dd5f02bd3..0cb5731a05 100644 --- a/docs/references/nextjs/overview.mdx +++ b/docs/references/nextjs/overview.mdx @@ -3,42 +3,28 @@ title: Clerk Next.js SDK description: Learn how to use Clerk to quickly and easily add secure authentication and user management to your Next.js application. --- -Clerk makes it simple to add authentication to your Next.js application. This documentation covers the capabilities and methods available from Clerk's Next.js SDK. - -## Guides - -- [Read session and user data](/docs/references/nextjs/read-session-data) -- [Add custom sign up and sign in pages](/docs/references/nextjs/custom-signup-signin-pages) -- [Integrate Clerk into your app with tRPC](/docs/references/nextjs/trpc) +Clerk makes it simple to add authentication to your Next.js application. This reference lists the features and methods available in Clerk's Next.js SDK. ## Client-side helpers -Because Clerk Next.js is a wrapper around Clerk React, you can utilize the hooks that Clerk React provides. These hooks give you access to the [`Clerk`](/docs/references/javascript/clerk/clerk) object, and a set of useful helper methods for signing in and signing up. You can learn more about these hooks [in the React SDK reference](/docs/references/react/overview). +Because the Next.js SDK is built on top of the Clerk React SDK, you can utilize the hooks that the React SDK provides. These hooks give you access to the [`Clerk`](/docs/references/javascript/clerk/clerk) object and a set of useful helper methods for signing in and signing up. Learn more about these hooks in the [React SDK reference](/docs/references/react/overview). -{/* TODO: We can use a partial here. */} + -- [`useUser()`](/docs/references/react/use-user) -- [`useClerk()`](/docs/references/react/use-clerk) -- [`useAuth()`](/docs/references/react/use-auth) -- [`useSignIn()`](/docs/references/react/use-sign-in) -- [`useSignUp()`](/docs/references/react/use-sign-up) -- [`useSession()`](/docs/references/react/use-session) -- [`useSessionList()`](/docs/references/react/use-session-list) -- [`useOrganization()`](/docs/references/react/use-organization) -- [`useOrganizationList()`](/docs/references/react/use-organization-list) +## Server-side helpers -## App router references +### App router -Clerk provides first-class support for the [Next.js App Router](https://nextjs.org/docs/app). The below methods and references show how to integrate Clerk features into applications that take advantage of the latest App Router and React Server Components features. +Clerk provides first-class support for the [Next.js App Router](https://nextjs.org/docs/app). The following references show how to integrate Clerk features into apps using the latest App Router and React Server Components features. - [`auth()`](/docs/references/nextjs/auth) - [`currentUser()`](/docs/references/nextjs/current-user) - [Route Handlers](/docs/references/nextjs/route-handlers) - [Server Actions](/docs/references/nextjs/server-actions) -## Pages router references +### Pages router -Clerk continues to provide drop-in support for the Next.js Pages Router. In addition to the main Clerk integration, several methods are available for instrumenting authentication within Pages Router-based applications. +Clerk continues to provide drop-in support for the Next.js Pages Router. In addition to the main Clerk integration, the following references are available for apps using Pages Router. - [`getAuth()`](/docs/references/nextjs/get-auth) - [`buildClerkProps()`](/docs/references/nextjs/build-clerk-props) @@ -47,7 +33,7 @@ Clerk continues to provide drop-in support for the Next.js Pages Router. In addi ### `Auth` object -Both `auth()` and `getAuth()` return an `Auth` object. This JavaScript object contains important information like session data, your user's ID, as well as their organization ID. Learn more about the `Auth` object [here](/docs/references/nextjs/auth-object). +Both `auth()` (App Router) and `getAuth()` (Pages Router) return an `Auth` object. This JavaScript object contains important information like the current user's session ID, user ID, and organization ID. Learn more about the [`Auth` object](/docs/references/nextjs/auth-object){{ target: '_blank' }}. ### `clerkMiddleware()` diff --git a/docs/references/react-router/custom-signup-signin-pages.mdx b/docs/references/react-router/custom-signup-signin-pages.mdx new file mode 100644 index 0000000000..1bb6e01d6d --- /dev/null +++ b/docs/references/react-router/custom-signup-signin-pages.mdx @@ -0,0 +1,91 @@ +--- +title: Build your own sign-up and sign-in pages for your React Router app with Clerk +description: Learn how to add custom sign-up and sign-in pages to your React Router app with Clerk's prebuilt components. +--- + +This guide shows you how to use the [``](/docs/components/authentication/sign-in) and [``](/docs/components/authentication/sign-up) components with the [React Router Splat route](https://reactrouter.com/start/framework/routing#splats) to build custom sign-up and sign-in pages for your React Router app. See the [quickstart tutorial](/docs/quickstarts/react-router) for a step-by-step guide. + +If the prebuilt components don't meet your specific needs or if you require more control over the logic, you can rebuild the existing Clerk flows using the Clerk API. For more information, see the [custom flow guides](/docs/custom-flows/overview). + + + ### Build a sign-up page + + The following example demonstrates how to render the [``](/docs/components/authentication/sign-up) component. + + ```tsx {{ filename: 'app/routes/sign-up.tsx' }} + import { SignUp } from '@clerk/react-router' + + export default function SignUpPage() { + return ( +
+

Sign up route

+ +
+ ) + } + ``` + + ### Build a sign-in page + + The following example demonstrates how to render the [``](/docs/components/authentication/sign-in) component. + + ```tsx {{ filename: 'app/routes/sign-in.tsx' }} + import { SignIn } from '@clerk/react-router' + + export default function SignInPage() { + return ( +
+

Sign in route

+ +
+ ) + } + ``` + + ### Configure routes + + React Router expects you to define routes in [`app/routes.ts`](https://reactrouter.com/start/framework/routing). Add the previously created sign-in and sign-up pages to your route configuration. + + ```tsx {{ filename: 'app/routes.ts', mark: [5, 6] }} + import { type RouteConfig, index, route } from '@react-router/dev/routes' + + export default [ + index('routes/home.tsx'), + route('sign-in/*', 'routes/sign-in.tsx'), + route('sign-up/*', 'routes/sign-up.tsx'), + ] satisfies RouteConfig + ``` + + ### Configure redirect behavior + + Update your environment variables to point to your custom sign-up and sign-in pages. Learn more about the available [environment variables](/docs/deployments/clerk-environment-variables). + + ```env {{ filename: '.env' }} + CLERK_SIGN_IN_FALLBACK_URL=/ + CLERK_SIGN_UP_FALLBACK_URL=/ + CLERK_SIGN_IN_URL=/sign-in + CLERK_SIGN_UP_URL=/sign-up + ``` + + These values control the behavior of the `` and `` components and when you visit the respective links at the bottom of each component. + + ### Visit your new pages + + Run your project with the following command: + + + ```bash {{ filename: 'terminal' }} + npm run dev + ``` + + ```bash {{ filename: 'terminal' }} + yarn dev + ``` + + ```bash {{ filename: 'terminal' }} + pnpm dev + ``` + + + Visit your new custom pages locally at [localhost:5173/sign-up](http://localhost:5173/sign-up) and [localhost:5173/sign-in](http://localhost:5173/sign-in). +
diff --git a/docs/references/react-router/get-auth.mdx b/docs/references/react-router/get-auth.mdx new file mode 100644 index 0000000000..9715c265c6 --- /dev/null +++ b/docs/references/react-router/get-auth.mdx @@ -0,0 +1,118 @@ +--- +title: '`getAuth()`' +description: The getAuth() helper retrieves authentication state from the request object. +--- + +The `getAuth()` helper retrieves authentication state from the request object. + +## Parameters + + + - `request` + + The request object. + + --- + + - `opts?` + + An optional object that can be used to configure the behavior of the `getAuth()` function. It accepts the following properties: + + - `secretKey?`: A string that represents the secret key used to sign the session token. If not provided, the secret key is retrieved from the environment variable `CLERK_SECRET_KEY`. + + +## Returns + +`getAuth()` returns the [`Auth`](/docs/references/nextjs/auth-object){{ target: '_blank' }} object. + +## Usage + +### Server data loading + +The following example demonstrates how to use `getAuth()` to protect a profile page route and load user data. +If the user is authenticated, their `userId` is passed to the Backend SDK's [`getUser()`](/docs/references/backend/user/get-user){{ target: '_blank' }} method to retrieve the user's information. + +```tsx {{ filename: 'app/routes/profile.tsx' }} +import { redirect } from 'react-router' +import { getAuth } from '@clerk/react-router/ssr.server' +import { createClerkClient } from '@clerk/react-router/api.server' +import type { Route } from './+types/profile' + +export async function loader(args: Route.LoaderArgs) { + const { userId } = await getAuth(args) + + if (!userId) { + return redirect('/sign-in?redirect_url=' + args.request.url) + } + + const user = await createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }).users.getUser( + userId, + ) + + return { + user: JSON.stringify(user), + } +} + +export default function Profile({ loaderData }: Route.ComponentProps) { + return ( +
+

Profile Data

+
+        {JSON.stringify(loaderData, null, 2)}
+      
+
+ ) +} +``` + +### Server action + +Unlike the previous example that loads data when the page loads, the following example uses `getAuth()` to only fetch user data after submitting the form. The helper runs on form submission, authenticates the user, and processes the form data. + +```tsx {{ filename: 'app/routes/profile-form.tsx' }} +import { redirect, Form } from 'react-router' +import { getAuth } from '@clerk/react-router/ssr.server' +import { createClerkClient } from '@clerk/react-router/api.server' +import type { Route } from './+types/profile-form' + +export async function action(args: Route.ActionArgs) { + const { userId } = await getAuth(args) + + if (!userId) { + return redirect('/sign-in?redirect_url=' + args.request.url) + } + + const formData = await args.request.formData() + const name = formData.get('name')?.toString() + + const user = await createClerkClient({ + secretKey: process.env.CLERK_SECRET_KEY, + }).users.getUser(userId) + + return { + name, + user: JSON.stringify(user), + } +} + +export default function ProfileForm({ actionData }: Route.ComponentProps) { + return ( +
+

Profile Data

+ +
+ + + +
+ + {actionData ? ( +
+          {JSON.stringify(actionData, null, 2)}
+        
+ ) : null} +
+ ) +} +``` diff --git a/docs/references/react-router/library-mode.mdx b/docs/references/react-router/library-mode.mdx new file mode 100644 index 0000000000..87e57aef0f --- /dev/null +++ b/docs/references/react-router/library-mode.mdx @@ -0,0 +1,128 @@ +--- +title: React Router library mode +description: Learn how to use Clerk with React Router in library mode to add authentication to your application. +--- + +> [!WARNING] +> The React Router SDK is currently in beta. + + + - Install `@clerk/react-router` + - Set your Clerk API keys + - Add `` + - Protect your pages + + +React Router can be used as a framework or as a standalone library. This guide explains how to add React Router authentication to an existing React application using library mode. To use React Router as a framework instead, see the [React Router quickstart](/docs/quickstarts/react-router). + + + ### Install `@clerk/react-router` + + Clerk's [React Router SDK](/docs/references/react-router/overview) provides prebuilt components, hooks, and stores to make it easy to integrate authentication and user management in your React Router app. + + Run the following command to install the SDK: + + + ```bash {{ filename: 'terminal' }} + npm install @clerk/react-router + ``` + + ```bash {{ filename: 'terminal' }} + yarn add @clerk/react-router + ``` + + ```bash {{ filename: 'terminal' }} + pnpm add @clerk/react-router + ``` + + + ### Set your Clerk API keys + + > [!NOTE] + > You will not need the Clerk Secret Key in React Router's library mode, as it should never be used on the client-side. + + + Add your Clerk Publishable Key to your `.env` file. This key can always be retrieved from the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page of the Clerk Dashboard. + + + + 1. In the Clerk Dashboard, navigate to the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page. + 1. In the **Quick Copy** section, copy your Clerk Publishable Key. + 1. Add your key to your `.env` file. + + The final result should resemble the following: + + + ```env {{ filename: '.env' }} + VITE_CLERK_PUBLISHABLE_KEY={{pub_key}} + ``` + + ### Add `` to your app + + + + You must pass your Publishable Key as a prop, as shown in the following example: + + ```tsx {{ filename: 'src/main.tsx', mark: [4, 8, [13, 17]] }} + import { StrictMode } from 'react' + import { createRoot } from 'react-dom/client' + import { BrowserRouter, Routes, Route } from 'react-router' + import { ClerkProvider } from '@clerk/react-router' + import './index.css' + import App from './App.tsx' + + const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY + + createRoot(document.getElementById('root')!).render( + + + + + } /> + + + + , + ) + ``` + + ### Create a header with Clerk components + + You can control which content signed-in and signed-out users can see with the [prebuilt control components](/docs/components/overview#what-are-control-components). The following example creates a header using the following components: + + - [``](/docs/components/control/signed-in): Children of this component can only be seen while **signed in**. + - [``](/docs/components/control/signed-out): Children of this component can only be seen while **signed out**. + - [``](/docs/components/user/user-button): Shows the signed-in user's avatar. Selecting it opens a dropdown menu with account management options. + - [``](/docs/components/unstyled/sign-in-button): An unstyled component that links to the sign-in page or displays the sign-in modal. + + ```tsx {{ filename: 'src/App.tsx' }} + import { SignInButton, SignedIn, SignedOut, UserButton } from '@clerk/react-router' + + export default function App() { + return ( +
+ + + + + + +
+ ) + } + ``` +
diff --git a/docs/references/react-router/overview.mdx b/docs/references/react-router/overview.mdx new file mode 100644 index 0000000000..b7669134cf --- /dev/null +++ b/docs/references/react-router/overview.mdx @@ -0,0 +1,33 @@ +--- +title: Clerk React Router SDK +description: Learn how to use Clerk to quickly and easily add secure authentication and user management to your React Router application. +--- + +> [!WARNING] +> The React Router SDK is currently in beta. + +Clerk makes it simple to add authentication to your React Router application. This reference lists the features and methods available in Clerk's React Router SDK. + +## Client-side helpers + +The Clerk React Router SDK is built on top of the Clerk React SDK and provides access to all of Clerk React's hooks. These hooks give you access to the [`Clerk`](/docs/references/javascript/clerk/clerk) object and a set of useful helper methods for signing in and signing up. Learn more about these hooks in the [React SDK reference](/docs/references/react/overview). + + + +## Server-side helpers + +The following references show how to integrate Clerk features into applications using React Router server functions and API routes. + +- [`getAuth()`](/docs/references/react-router/get-auth) +- [`rootAuthLoader()`](/docs/references/react-router/root-auth-loader) + +### `Auth` object + +The `getAuth()` method returns an `Auth` object. This JavaScript object contains important information like the current user's session ID, user ID, and organization ID. Learn more about the [`Auth` object](/docs/references/nextjs/auth-object){{ target: '_blank' }}. + +## React Router implementations + +React Router can be integrated with Clerk in two ways: + +- As a framework (recommended): Configure your app using [Clerk's React Router SDK](/docs/quickstarts/react-router) +- As a library: Manually integrate React Router into your React + Vite app using [library mode](/docs/references/react-router/library-mode) diff --git a/docs/references/react-router/read-session-data.mdx b/docs/references/react-router/read-session-data.mdx new file mode 100644 index 0000000000..23398a1e38 --- /dev/null +++ b/docs/references/react-router/read-session-data.mdx @@ -0,0 +1,54 @@ +--- +title: Read session and user data in your React Router app with Clerk +description: Learn how to use Clerk's hooks and helpers to access the active session and user data in your React Router application. +--- + +Clerk provides a set of [hooks and helpers](/docs/references/react-router/overview#client-side-helpers) that you can use to access the active session and user data in your React Router application. Here are examples of how to use these helpers in both the client and server-side to get you started. + +## Server-side + +To access active session and user data on the server-side, use the `getAuth()` helper. See the [reference documentation](/docs/references/react-router/get-auth) for more information, including code examples. + +## Client-side + +To access active session and user data on the client-side, use Clerk's `useAuth()` and `useUser()` hooks. + +### `useAuth()` + +The [`useAuth()`](/docs/references/react/use-auth){{ target: '_blank' }} hook provides information about the current auth state, as well as helper methods to manage the current active session. The hook returns `userId`, which can be used to protect your routes, as shown in the following example: + +```tsx {{ filename: 'app/routes/use-auth.tsx' }} +import { useAuth } from '@clerk/react-router' + +export default function UseAuthPage() { + const { isLoaded, userId } = useAuth() + + // Return null if the user signs out while on the page + // or if the auth state is still loading + if (!isLoaded || !userId) { + return null + } + + return
Hello, {userId}!
+} +``` + +### `useUser()` + +The [`useUser()`](/docs/references/react/use-user){{ target: '_blank' }} hook provides the current user's [`User`](/docs/references/javascript/user/user){{ target: '_blank' }} object, which holds all of the information for a user of your application and provides a set of methods to manage their account. + +```tsx {{ filename: 'app/routes/use-user.tsx' }} +import { useUser } from '@clerk/react-router' + +export default function UseUserPage() { + const { isLoaded, isSignedIn, user } = useUser() + + // Return null if the user signs out while on the page + // or if the auth state is still loading + if (!isLoaded || !isSignedIn) { + return null + } + + return
Hello, {user.firstName}!
+} +``` diff --git a/docs/references/react-router/root-auth-loader.mdx b/docs/references/react-router/root-auth-loader.mdx new file mode 100644 index 0000000000..cf465b889e --- /dev/null +++ b/docs/references/react-router/root-auth-loader.mdx @@ -0,0 +1,159 @@ +--- +title: '`rootAuthLoader()`' +description: The rootAuthLoader() function configures Clerk to handle authentication state for React Router routes. +--- + +The `rootAuthLoader()` function configures Clerk to handle authentication state for React Router routes, allowing easy access to user session information in your app. + +## Configure `rootAuthLoader()` + +In your `root.tsx` file, add `rootAuthLoader` to the `loader` function. If your app doesn't have a loader function yet, you'll need to add it manually. + +```tsx {{ filename: 'app/root.tsx' }} +import { rootAuthLoader } from '@clerk/react-router/ssr.server' +import type { Route } from './+types/root' + +export async function loader(args: Route.LoaderArgs) { + return rootAuthLoader(args) +} +``` + +You can also pass [options](#root-auth-loader-options) to the `rootAuthLoader()` as the second argument. + +```tsx {{ filename: 'app/root.tsx', mark: [5] }} +import { rootAuthLoader } from '@clerk/react-router/ssr.server' +import type { Route } from './+types/root' + +export async function loader(args: Route.LoaderArgs) { + return rootAuthLoader(args, { signInUrl: '/sign-in' }) +} +``` + +### Loading additional data + +If you need to load additional data, you can pass your loader directly to `rootAuthLoader()` as the second argument. The options object is passed as the third argument. + +```tsx {{ filename: 'app/root.tsx', mark: [7, 13] }} +import { rootAuthLoader } from '@clerk/react-router/ssr.server' +import type { Route } from './+types/root' + +export async function loader(args: Route.LoaderArgs) { + return rootAuthLoader( + args, + ({ request, context, params }) => { + // Loader + const { userId } = request.auth + + return { userId } + }, + { signInUrl: '/sign-in' }, // Options + ) +} +``` + +## `rootAuthLoader()` options + + + - `secretKey?` + - `string` + + The Clerk Secret Key from the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page in the Clerk Dashboard. + + --- + + - `jwtKey?` + - `string` + + The PEM public key from the **[**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page -> Show JWT public key -> PEM Public Key** section in the Clerk Dashboard. For more information, refer to [Manual JWT verification](/docs/backend-requests/handling/manual-jwt). + + --- + + - `publishableKey?` + - `string` + + The Clerk Publishable Key from the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page in the Clerk Dashboard. + + --- + + - `domain?` + - `string` + + The domain of a [satellite application](/docs/advanced-usage/satellite-domains) in a multi-domain setup. + + --- + + - `isSatellite?` + - `boolean` + + Whether the instance is a satellite domain in a multi-domain setup. Defaults to `false`. + + --- + + - `proxyUrl?` + - `string` + + The proxy URL from a multi-domain setup. + + --- + + - `sdkMetadata?` + - `{ name: string, version: string }` + + Metadata about the SDK. + + --- + + - `telemetry?` + - `{ disabled: boolean, debug: boolean }` + + [Telemetry](/docs/telemetry) configuration. + + --- + + - `userAgent?` + - `string` + + The User-Agent request header passed to the Clerk API. + + --- + + - `apiUrl?` + - `string` + + The [Clerk Backend API](/docs/reference/backend-api){{ target: '_blank' }} endpoint. Defaults to `'https://api.clerk.com'`. + + --- + + - `apiVersion?` + - `string` + + The version passed to the Clerk API. Defaults to `'v1'`. + + --- + + - `audience?` + - `string | string[]` + + A string or list of [audiences](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3). + + --- + + - `authorizedParties?` + - `string[]` + + An allowlist of origins to verify against, to protect your application from the subdomain cookie leaking attack.
For example: `['http://localhost:3000', 'https://example.com']` + + --- + + - `signInUrl?` + - `string` + + The full URL or path to the sign in page. Use this property to provide the target of the 'Sign in' link that's rendered. It's recommended to use [the environment variable](/docs/deployments/clerk-environment-variables#sign-in-and-sign-up-redirects) instead. + + --- + + - `signUpUrl?` + - `string` + + The full URL or path to the sign up page. Use this property to provide the target of the 'Sign up' link that's rendered. It's recommended to use [the environment variable](/docs/deployments/clerk-environment-variables#sign-in-and-sign-up-redirects) instead. +
diff --git a/docs/references/react/add-react-router.mdx b/docs/references/react/add-react-router.mdx deleted file mode 100644 index ed6e50fc46..0000000000 --- a/docs/references/react/add-react-router.mdx +++ /dev/null @@ -1,334 +0,0 @@ ---- -title: Add React Router to your Clerk-powered React application -description: Learn how to add React Router to your React application using their Data API router. ---- - - - - Install `react-router-dom` - - Create components for your routes - - Create layouts - - Wire layouts and routes up with `createBrowserRouter` - - -> [!WARNING] -> This tutorial is written for [React Router 6](https://reactrouter.com/6.28.0/home) and doesn't support [loaders](https://reactrouter.com/6.28.0/route/loader) and [actions](https://reactrouter.com/6.28.0/route/action). - -Learn how to add React Router to your application using React Router's new Data API router. This tutorial will cover configuring layouts and setting up protected routes. - - - ### Install `react-router-dom` - - React Router's `react-router-dom` is a mature, battle tested routing package for React that gives you many options. As it is the most popular routing option, it will be used for this guide. - - - ```bash {{ filename: 'terminal' }} - npm install react-router-dom - ``` - - ```bash {{ filename: 'terminal' }} - yarn add react-router-dom - ``` - - ```bash {{ filename: 'terminal' }} - pnpm add react-router-dom - ``` - - - ### Create components for your routes - - The exact routes you will need depends on your application. For this guide, you will create `/`, `/contact`, `/dashboard`, `/sign-in`, and `sign-up` routes. The `/dashboard` route will contain a default route (`/dashboard/`) and an invoices route (`/dashboard/invoices`). The first step will be creating basic components for these routes. - - Use the tabs below to find the example components and recreate these files using the path from each tab. - - - ```tsx {{ filename: 'src/routes/index.tsx' }} - import { Link } from 'react-router-dom' - - export default function IndexPage() { - return ( -
-

This is the index page

-
-
    -
  • - Sign Up -
  • -
  • - Sign In -
  • -
  • - Contact -
  • -
  • - Dashboard -
  • -
-
-
- ) - } - ``` - - ```tsx {{ filename: 'src/routes/contact.tsx' }} - import { Link } from 'react-router-dom' - - export default function ContactPage() { - return ( - <> -

Contact

-

- This is a public page meant to contain a contact form and other related contact details. -

-
    -
  • - Return to Index -
  • -
  • - Dashboard -
  • -
- - ) - } - ``` - - ```tsx {{ filename: 'src/routes/sign-in.tsx' }} - import { SignIn } from '@clerk/clerk-react' - - export default function SignInPage() { - return - } - ``` - - ```tsx {{ filename: 'src/routes/sign-up.tsx' }} - import { SignUp } from '@clerk/clerk-react' - - export default function SignUpPage() { - return - } - ``` - - ```tsx {{ filename: 'src/routes/dashboard.tsx' }} - import { Link } from 'react-router-dom' - - export default function DashboardPage() { - return ( - <> -

Dashboard page

-

This is a protected page.

- -
    -
  • - Invoices -
  • -
  • - Return to index -
  • -
- - ) - } - ``` - - ```tsx {{ filename: 'src/routes/dashboard.invoices.tsx' }} - import { Link } from 'react-router-dom' - - export default function InvoicesPage() { - return ( - <> -

Invoices page

-

This is a protected page.

- -
    -
  • - Dashboard -
  • -
  • - Return to index -
  • -
- - ) - } - ``` -
- - ### Create layouts - - You're going to create two layouts for your application. One will mount [``](/docs/components/clerk-provider) and act as a top level layout. It will also be a place for a header, footer, and other standard elements for your application. - - The second layout will be non-rendering and will protect everything in the `/dashboard` route. This avoids the need for per-page auth checks or for using Clerk's control components. - - - ```tsx {{ filename: 'src/layouts/root-layout.tsx' }} - import { Link, Outlet, useNavigate } from 'react-router-dom' - import { ClerkProvider, SignedIn, SignedOut, UserButton } from '@clerk/clerk-react' - - const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY - - if (!PUBLISHABLE_KEY) { - throw new Error('Missing Publishable Key') - } - - export default function RootLayout() { - const navigate = useNavigate() - - return ( - navigate(to)} - routerReplace={(to) => navigate(to, { replace: true })} - publishableKey={PUBLISHABLE_KEY} - > -
-
-
-

Clerk + React + React Router App

-
- - - - - Sign In - -
-
-
- -
-
- ) - } - ``` - - ```tsx {{ filename: 'src/layouts/dashboard-layout.tsx' }} - import * as React from 'react' - import { useAuth } from '@clerk/clerk-react' - import { Outlet, useNavigate } from 'react-router-dom' - - export default function DashboardLayout() { - const { userId, isLoaded } = useAuth() - const navigate = useNavigate() - - console.log('test', userId) - - React.useEffect(() => { - if (isLoaded && !userId) { - navigate('/sign-in') - } - }, [isLoaded]) - - if (!isLoaded) return 'Loading...' - - return - } - ``` -
- - #### Key Takeaways - - - The new root-layout.tsx has a simple header that includes the `` and a link to the `/sign-in` page instead of a ``. The rendering of these is controlled by the `` and `` control components. This is very similar to the [Embed the `` and ``](/docs/quickstarts/react#embed-the-user-button-and-sign-in-button) step from the [React Quickstart](/docs/quickstarts/react). - - Both the layouts contain an `` component from `react-router-dom`. This behaves similar to `{children}` in Next.js or more generic React components. You will take advantage of this component in the next step. - - ### Wire layouts and routes up with `createBrowserRouter` - - With all the routes and layouts you need created, you now need to wire up the layouts and the routes with the `createBrowserRouter` function from `react-router-dom`. This will use the Data API (aka Data Router) to configure your application. - - You can start by removing `src/App.tsx`—the contents of that file were moved to `src/layouts/root-layout.tsx`. - - In `src/main.tsx`, import `RouterProvider` and `createBrowserRouter()` from `react-router-dom`, as well as all of the default components from the layouts and routes you created. Replace the contents inside of `` with only ` `. Lastly, you will build the `router` using `createBrowserRouter()`. - - ```tsx {{ filename: 'src/main.tsx' }} - import React from 'react' - import ReactDOM from 'react-dom/client' - import './index.css' - import { RouterProvider, createBrowserRouter } from 'react-router-dom' - - // Import the layouts - import RootLayout from './layouts/root-layout' - import DashboardLayout from './layouts/dashboard-layout' - - // Import the components - import IndexPage from './routes' - import ContactPage from './routes/contact' - import SignInPage from './routes/sign-in' - import SignUpPage from './routes/sign-up' - import DashboardPage from './routes/dashboard' - import InvoicesPage from './routes/dashboard.invoices' - - const router = createBrowserRouter([ - { - element: , - children: [ - { path: '/', element: }, - { path: '/contact', element: }, - { path: '/sign-in/*', element: }, - { path: '/sign-up/*', element: }, - { - element: , - path: 'dashboard', - children: [ - { path: '/dashboard', element: }, - { path: '/dashboard/invoices', element: }, - ], - }, - ], - }, - ]) - - ReactDOM.createRoot(document.getElementById('root')!).render( - - - , - ) - ``` - - Visit [`http://localhost:5173`](http://localhost:5173) and explore your app's pages. - - #### Key Takeaways - - - The top most object in the `router` is the `` component, and everything else is a child. Any child route will be mounted where the `` component is inside the root layout. This wraps the entire application with `` and allows you to add a header, footer, sidebars and other pieces that will be available to the entire application. - - Several routes are direct children of the root layout. These are all public routes. You can use control components like `` or check the `userId` from `useAuth()` if you want to make content protected. - - The `` is child of the root layout, renders nothing, and has a check to see if the `userId` exists. This will confirm that a user is signed in. If the `userId` is not truthy, then the user will be redirected to the `/sign-in` route to sign-in. That protects all pages in the `/dashboard` route. All children of `/dashboard` will be mounted inside of the `` component in the dashboard layout. -
- -Your application is setup with `react-router-dom` and ready for you to add more layouts and routes as needed! If you want to get started using a template from this guide, clone the following repository and then checkout the `integrate-react-router-dom-using-data-router-method` branch. - -- [Clerk + React Quickstart](https://github.com/clerk/clerk-react-quickstart) - -### Next steps - - - - [Customization & Localization](/docs/customization/overview) - - Learn how to customize and localize the Clerk components. - - --- - - - [Authentication Components](/docs/components/authentication/sign-in) - - Learn more about all our authentication components. - - --- - - - [Client Side Helpers](/docs/references/react/use-user) - - Learn more about our client-side helpers and how to use them. - diff --git a/docs/references/react/overview.mdx b/docs/references/react/overview.mdx index 50b72d2f59..0545b4f8a1 100644 --- a/docs/references/react/overview.mdx +++ b/docs/references/react/overview.mdx @@ -1,19 +1,47 @@ --- title: Clerk React SDK -description: Learn how to integrate React into your Clerk application. +description: Learn how to integrate Clerk into your React application using the Clerk React SDK. --- -The Clerk React SDK is a wrapper around the Clerk JavaScript SDK. It is the recommended way to integrate Clerk into your React application. +The React SDK is built on top of the JavaScript SDK, and is the recommended method for integrating Clerk into your React application. -> [!WARNING] -> If you are using Next.js, install the `@clerk/nextjs` package, as `@clerk/clerk-react` is incompatible. See the [Next.js](/docs/references/nextjs/overview) documentation for more information. +## Key features -Clerk React provides React.js implementations of [Clerk components](/docs/components/overview); highly customizable, prebuilt components that you can use to build beautiful user management applications. You can find display components for building [sign-in](/docs/components/authentication/sign-in), [sign-up](/docs/components/authentication/sign-up), [account switching](/docs/components/user/user-button), and [user profile management](/docs/components/user/user-profile) pages as well as flow [control components](/docs/components/control/signed-in) that act as helpers for implementing a seamless authentication experience. +### Pre-built components -Clerk React provides a suite of [custom hooks](/docs/references/react/use-user). These hooks give you access to the [`Clerk` object](/docs/references/javascript/clerk/clerk), and a set of useful helper methods for signing in and signing up. +The React SDK provides access to [Clerk components](/docs/components/overview) for user and organization management, including: -## Setting up Clerk React +- [Sign-in](/docs/components/authentication/sign-in) +- [Sign-up](/docs/components/authentication/sign-up) +- [Account switching](/docs/components/user/user-button) +- [User profile management](/docs/components/user/user-profile) +- [Organization switching](/docs/components/organization/organization-switcher) +- [Organization management](/docs/components/organization/organization-profile) +- [Control components](/docs/components/control/signed-in) -You need to create a Clerk application in the Clerk Dashboard before you can set up Clerk React. For more information, see the [setup guide](/docs/quickstarts/setup-clerk). +### Custom hooks -Once a Clerk application has been created, you can install and start using Clerk React in your application. [The quickstart guide](/docs/quickstarts/react) will have all the information you need to get started. +The React SDK provides access to custom hooks that provide direct access to the [`Clerk` object](/docs/references/javascript/clerk/clerk), a user's [`User` object](/docs/references/javascript/user/user), and helper methods for authentication flows. + + + +## Framework-specific SDKs + +> [!IMPORTANT] +> Clerk provides optimized SDKs for specific React frameworks. If you're using one of the supported frameworks below, you should use its dedicated SDK instead of `@clerk/clerk-react`. +> +> For example, Next.js applications **must** use `@clerk/nextjs` as `@clerk/clerk-react` is not compatible. + +Clerk offers framework-specific SDKs that are customized to provide the better developer experience and integration with each framework's features. Choose the appropriate SDK based on your framework: + +| Framework | Package | Docs | +| - | - | - | +| Next.js | `@clerk/nextjs` | [Next.js SDK](/docs/references/nextjs/overview) | +| React Router | `@clerk/clerk-react-router` | [React Router SDK](/docs/references/react-router/overview) | +| Remix | `@clerk/remix` | [Remix SDK](/docs/references/remix/clerk-app) | +| Astro | `@clerk/astro` | [Astro SDK](/docs/references/astro/overview) | +| Tanstack Start | `@clerk/tanstack-start` | [Tanstack Start SDK](/docs/references/tanstack-start/overview) | + +## Set up Clerk React + +Before you can add Clerk to your React application, you must create a Clerk app in the Clerk Dashboard. To get started, follow the [setup guide](/docs/quickstarts/setup-clerk). Then, follow the [quickstart guide](/docs/quickstarts/react) to set up the React SDK in your app. diff --git a/docs/references/remix/custom-signup-signin-pages.mdx b/docs/references/remix/custom-signup-signin-pages.mdx index 3157c9702e..f0a2cb40dd 100644 --- a/docs/references/remix/custom-signup-signin-pages.mdx +++ b/docs/references/remix/custom-signup-signin-pages.mdx @@ -13,7 +13,7 @@ The functionality of the components are controlled by the instance settings you > Just getting started with Clerk and Remix? See the [quickstart tutorial](/docs/quickstarts/remix)! - ## Build your sign-up page + ### Build your sign-up page The following example demonstrates how to render the [``](/docs/components/authentication/sign-up) component. @@ -30,7 +30,7 @@ The functionality of the components are controlled by the instance settings you } ``` - ## Build your sign-in page + ### Build your sign-in page The following example demonstrates how to render the [``](/docs/components/authentication/sign-in) component. @@ -47,7 +47,7 @@ The functionality of the components are controlled by the instance settings you } ``` - ## Configure your sign-up and sign-in pages + ### Configure your sign-up and sign-in pages @@ -78,7 +78,7 @@ The functionality of the components are controlled by the instance settings you These values control the behavior of the components when you sign in or sign up and when you click on the respective links at the bottom of each component. - ## Visit your new pages + ### Visit your new pages Run your project with the following terminal command from the root directory of your project: diff --git a/docs/telemetry.mdx b/docs/telemetry.mdx index 770a82178b..e34347da2b 100644 --- a/docs/telemetry.mdx +++ b/docs/telemetry.mdx @@ -80,7 +80,9 @@ If you are using `@clerk/clerk-react` directly, or using an SDK that doesn't hav ### Framework specific instructions - + ```env {{ filename: '.env.local' }} NEXT_PUBLIC_CLERK_TELEMETRY_DISABLED=1 ``` @@ -109,4 +111,12 @@ If you are using `@clerk/clerk-react` directly, or using an SDK that doesn't hav ```env {{ filename: '.env.local' }} PUBLIC_CLERK_TELEMETRY_DISABLED=1 ``` + + ```env {{ filename: '.env' }} + VITE_CLERK_TELEMETRY_DISABLED=1 + ``` + + ```env {{ filename: '.env' }} + VITE_CLERK_TELEMETRY_DISABLED=1 + ``` diff --git a/docs/troubleshooting/create-a-minimal-reproduction.mdx b/docs/troubleshooting/create-a-minimal-reproduction.mdx index e6865777ae..7018ee20f3 100644 --- a/docs/troubleshooting/create-a-minimal-reproduction.mdx +++ b/docs/troubleshooting/create-a-minimal-reproduction.mdx @@ -19,9 +19,11 @@ The best way to create a minimal reproduction is to start fresh, with a minimal - [Vanilla JS](https://github.com/clerkinc/clerk-js-starter) - [Expo](https://github.com/clerkinc/clerk-expo-starter) - [Remix](https://github.com/clerk/clerk-remix-v2) +- [React Router](https://github.com/clerk/clerk-react-router-quickstart) - [Redwood](https://github.com/clerkinc/clerk-redwood-starter) - [Rails](https://github.com/clerkinc/clerk-rails-starter) - [Chrome Extension](https://github.com/clerkinc/clerk-chrome-extension-starter) +- [Tanstack Start](https://github.com/clerk/clerk-tanstack-start-quickstart) ## Steps to create a minimal reproduction From a13343b37a1c6c9d985c1ff6b68b73ecc4d572b8 Mon Sep 17 00:00:00 2001 From: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:56:59 -0500 Subject: [PATCH 29/36] (chore) fix format for component references (#1796) Co-authored-by: victoria --- CONTRIBUTING.md | 2 +- docs/advanced-usage/satellite-domains.mdx | 2 +- docs/guides/architecture-scenarios.mdx | 2 +- docs/guides/authjs-migration.mdx | 6 +++--- docs/quickstarts/chrome-extension.mdx | 2 +- docs/quickstarts/expo.mdx | 2 +- docs/quickstarts/nextjs.mdx | 2 +- docs/quickstarts/react.mdx | 2 +- docs/quickstarts/tanstack-start.mdx | 2 +- docs/telemetry.mdx | 2 +- styleguides/STYLEGUIDE.md | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7b1f6158d2..4136a9f280 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -575,7 +575,7 @@ The `` component is used at the beginning of a tutorial-type con - Install `@clerk/nextjs` - Set up your environment keys to test your app locally -- Add `` to your application +- Add `` to your application - Use Clerk middleware to implement route-specific authentication - Create a header with Clerk components for users to sign in and out diff --git a/docs/advanced-usage/satellite-domains.mdx b/docs/advanced-usage/satellite-domains.mdx index 9a22e430bf..5ffb193f48 100644 --- a/docs/advanced-usage/satellite-domains.mdx +++ b/docs/advanced-usage/satellite-domains.mdx @@ -115,7 +115,7 @@ To access authentication state from a satellite domain, users will be transparen # CLERK_SIGN_UP_URL=http://localhost:3000/sign-up ``` - - You will also need to add the `allowedRedirectOrigins` property to `` on your _primary domain app_ to ensure that the redirect back from primary to satellite domain works correctly. For example: + - You will also need to add the `allowedRedirectOrigins` property to `` on your _primary domain app_ to ensure that the redirect back from primary to satellite domain works correctly. For example: ```tsx {{ filename: 'app/layout.tsx' }} diff --git a/docs/guides/architecture-scenarios.mdx b/docs/guides/architecture-scenarios.mdx index 9ffecf275c..68cb423248 100644 --- a/docs/guides/architecture-scenarios.mdx +++ b/docs/guides/architecture-scenarios.mdx @@ -56,7 +56,7 @@ Clerk offers a number of building blocks to help integrate organizations into yo - The [`` component](/docs/components/organization/organization-switcher) provides a way for your users to select which organization is active. The [`useOrganizationList()` hook](/docs/organizations/custom-organization-switcher) can be used for more control. - The [`useOrganization()` hook](/docs/references/react/use-organization) can be used to fetch the current, active organization. -- The [`` component](/docs/components/protect) enables you to limit who can view certain pages based on their role. Additionally, Clerk exposes a number of helper functions, such as [`auth()`](/docs/references/nextjs/auth), and hooks, such as [`useAuth()`](/docs/references/react/use-auth#how-to-use-the-use-auth-hook), to check the user's authorization throughout your app and API endpoints. +- The [`` component](/docs/components/protect) enables you to limit who can view certain pages based on their role. Additionally, Clerk exposes a number of helper functions, such as [`auth()`](/docs/references/nextjs/auth), and hooks, such as [`useAuth()`](/docs/references/react/use-auth#how-to-use-the-use-auth-hook), to check the user's authorization throughout your app and API endpoints. The organization's ID should be stored in your database alongside each resource so that it can be used to filter and query the resources that should be rendered or returned according to the active organization. diff --git a/docs/guides/authjs-migration.mdx b/docs/guides/authjs-migration.mdx index f08dfd11e0..0ff9014a9e 100644 --- a/docs/guides/authjs-migration.mdx +++ b/docs/guides/authjs-migration.mdx @@ -23,7 +23,7 @@ description: Learn how to migrate an application using Auth.js to use Clerk for > - Install `@clerk/nextjs` - Set environment variables - - Wrap your Next.js app in `` + - Wrap your Next.js app in `` - Set up sign-up and sign-in UI - Protect your app - Read user and session data @@ -67,9 +67,9 @@ This guide shows how to migrate an application using Auth.js (formerly NextAuth. CLERK_SECRET_KEY={{secret}} ``` - ### Wrap your Next.js app in `` + ### Wrap your Next.js app in `` - Remove the `` provider from Auth.js and replace it with ``. + Remove the `` provider from Auth.js and replace it with ``. diff --git a/docs/quickstarts/chrome-extension.mdx b/docs/quickstarts/chrome-extension.mdx index 3cb0d1d644..f361d050e4 100644 --- a/docs/quickstarts/chrome-extension.mdx +++ b/docs/quickstarts/chrome-extension.mdx @@ -21,7 +21,7 @@ description: Add authentication and user management to your Chrome Extension wit - Create a new app with Plasmo - Install `@clerk/chrome-extension` - Set your Clerk API keys - - Add `` and Clerk components to your app + - Add `` and Clerk components to your app - Configure your app to use a consistent CRX ID - Build, load, and test your Chrome Extension diff --git a/docs/quickstarts/expo.mdx b/docs/quickstarts/expo.mdx index 572092eba3..c9d126d8cf 100644 --- a/docs/quickstarts/expo.mdx +++ b/docs/quickstarts/expo.mdx @@ -27,7 +27,7 @@ description: Add authentication and user management to your Expo app with Clerk. > - Install `@clerk/expo` - Set your Clerk API keys - - Add `` + - Add `` - Protect specific pages with authentication - Use Clerk hooks to enable users to sign in and out diff --git a/docs/quickstarts/nextjs.mdx b/docs/quickstarts/nextjs.mdx index d7222bc320..7c6a8bcda1 100644 --- a/docs/quickstarts/nextjs.mdx +++ b/docs/quickstarts/nextjs.mdx @@ -21,7 +21,7 @@ description: Add authentication and user management to your Next.js app with Cle - Install `@clerk/nextjs` - Set your Clerk API keys - Add `clerkMiddleware()` - - Add `` and Clerk components + - Add `` and Clerk components diff --git a/docs/quickstarts/react.mdx b/docs/quickstarts/react.mdx index 21ba2e4f7f..a7384e1c8d 100644 --- a/docs/quickstarts/react.mdx +++ b/docs/quickstarts/react.mdx @@ -23,7 +23,7 @@ description: Add authentication and user management to your React app with Clerk - Create a new React app using Vite - Install `@clerk/clerk-react` - Set your Clerk API keys - - Add `` + - Add `` - Create a header with Clerk components for users to sign in and out diff --git a/docs/quickstarts/tanstack-start.mdx b/docs/quickstarts/tanstack-start.mdx index 4363013d83..909bb5bc3e 100644 --- a/docs/quickstarts/tanstack-start.mdx +++ b/docs/quickstarts/tanstack-start.mdx @@ -26,7 +26,7 @@ description: Learn how to use Clerk to quickly and easily add secure authenticat - Install `@clerk/tanstack-start` - Set your Clerk API keys - Add `createClerkHandler()` - - Add `` + - Add `` - Protect your pages diff --git a/docs/telemetry.mdx b/docs/telemetry.mdx index e34347da2b..9e5dfc27ab 100644 --- a/docs/telemetry.mdx +++ b/docs/telemetry.mdx @@ -72,7 +72,7 @@ CLERK_TELEMETRY_DISABLED=1 ### `telemetry` prop -If you are using `@clerk/clerk-react` directly, or using an SDK that doesn't have environment variable support, you can opt out by passing the `telemetry` prop to ``: +If you are using `@clerk/clerk-react` directly, or using an SDK that doesn't have environment variable support, you can opt out by passing the `telemetry` prop to ``: ```tsx diff --git a/styleguides/STYLEGUIDE.md b/styleguides/STYLEGUIDE.md index 4a6de61262..83c03cdbba 100644 --- a/styleguides/STYLEGUIDE.md +++ b/styleguides/STYLEGUIDE.md @@ -397,7 +397,7 @@ Component references should be wrapped in `< />` if they are self closing. Other The last case is incorrect because the `` component will never wrap children, and therefore, should have a self-closing tag. -> Use the `` component. +> Use the `` component. The last case is incorrect because the `` component will always wrap children and will never be self-closing. From 9a830c50d589b668e9216ac5d32cc357c1f84a39 Mon Sep 17 00:00:00 2001 From: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:57:08 -0500 Subject: [PATCH 30/36] (chore) fix signUpUrl prop description on clerkprovider (#1799) Co-authored-by: victoria --- docs/components/clerk-provider.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/components/clerk-provider.mdx b/docs/components/clerk-provider.mdx index ce49730c31..bcda26af27 100644 --- a/docs/components/clerk-provider.mdx +++ b/docs/components/clerk-provider.mdx @@ -209,7 +209,7 @@ The recommended approach is to wrap your entire app with `` at th - `signUpUrl` - `string` - This URL will be used for any redirects that might happen and needs to point to your primary application on the client-side. This option is optional for production instances and required for development instances. It's recommended to use [the environment variable](/docs/deployments/clerk-environment-variables#sign-in-and-sign-up-redirects) instead. + This URL will be used for any redirects that might happen and needs to point to your primary application on the client-side. This option is optional for production instances but **must be set for a satellite application in a development instance.** It's recommended to use [the environment variable](/docs/deployments/clerk-environment-variables#sign-in-and-sign-up-redirects) instead. --- From 8bf4b2b34637bfcccb018ca8ab82dc0fa9bd9ad9 Mon Sep 17 00:00:00 2001 From: Stefanos Anagnostou Date: Thu, 12 Dec 2024 22:01:03 +0200 Subject: [PATCH 31/36] Add the Expo Offline support page (#1781) Co-authored-by: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> --- docs/manifest.json | 4 ++ docs/manifest.schema.json | 3 +- docs/references/expo/offline-support.mdx | 73 ++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 docs/references/expo/offline-support.mdx diff --git a/docs/manifest.json b/docs/manifest.json index 4b6bc45721..4973d041a6 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -2313,6 +2313,10 @@ { "title": "Use biometrics with local credentials", "href": "/docs/references/expo/local-credentials" + }, + { + "title": "Offline support", + "href": "/docs/references/expo/offline-support" } ] ] diff --git a/docs/manifest.schema.json b/docs/manifest.schema.json index d2e07cba0d..1909c9e4e3 100644 --- a/docs/manifest.schema.json +++ b/docs/manifest.schema.json @@ -138,7 +138,8 @@ "user-circle", "user-dotted-circle", "vue", - "x" + "x", + "expo" ] } } diff --git a/docs/references/expo/offline-support.mdx b/docs/references/expo/offline-support.mdx new file mode 100644 index 0000000000..a281071efa --- /dev/null +++ b/docs/references/expo/offline-support.mdx @@ -0,0 +1,73 @@ +--- +title: Enable offline support in your Expo app +description: Learn how to enable offline support in your Expo app with Clerk. +--- + +> [!WARNING] +> **This is an experimental API.** +> +> The `__experimental_resourceCache` property introduced in this guide is an experimental feature. It is subject to change in future updates, so use it cautiously in production environments. Ensure thorough testing and stay informed through [the package's changelog](https://github.com/clerk/javascript/blob/main/packages/expo/CHANGELOG.md). + +The Clerk Expo SDK provides enhanced offline support to improve reliability and user experience. This update enables your app to bootstrap offline using cached Clerk resources, ensuring quick initialization without requiring an internet connection. + +It offers the following benefits: + +- Initialization of the Clerk SDK is now more resilient to network failures. +- Faster resolution of the `isLoaded` property and the [``](/docs/components/control/clerk-loaded) control component with only a single network fetch attempt. If the fetch fails, it gracefully falls back to cached resources. +- Network errors are no longer muted, allowing developers to catch and handle them effectively in their custom flows. +- The [`getToken()`](/docs/references/javascript/session#get-token) function in the `useAuth()` hook now supports returning cached tokens, minimizing disruptions caused by network failures. + +## How to enable offline support + +To enable offline support in your Expo app, follow these steps: + + + ### Install the necessary peer dependencies + + The `expo-secure-store` package is required to use the offline support feature. + + + ```bash {{ filename: 'terminal' }} + npm install expo-secure-store + ``` + + ```bash {{ filename: 'terminal' }} + yarn add expo-secure-store + ``` + + ```bash {{ filename: 'terminal' }} + pnpm add expo-secure-store + ``` + + + ### Use the `__experimental_resourceCache` property on `ClerkProvider` + + On [``](/docs/components/clerk-provider), pass the `secureStore` object to the `__experimental_resourceCache` property, as shown in the following example: + + ```tsx {{ filename: 'app/_layout.tsx', mark: [4, [14, 18]] }} + import { ClerkProvider, ClerkLoaded } from '@clerk/clerk-expo' + import { Slot } from 'expo-router' + import { tokenCache } from '../token-cache' + import { secureStore } from '@clerk/clerk-expo/secure-store' + + export default function RootLayout() { + const publishableKey = process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY! + + if (!publishableKey) { + throw new Error('Add EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY to your .env file') + } + + return ( + + + + + + ) + } + ``` + From 2d257c73849018e5af9126c64a57974215b58382 Mon Sep 17 00:00:00 2001 From: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> Date: Thu, 12 Dec 2024 17:25:07 -0500 Subject: [PATCH 32/36] (chore) DOCS-9680 add list of components to component reference overview (#1800) --- docs/components/overview.mdx | 39 +++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/docs/components/overview.mdx b/docs/components/overview.mdx index 30ef4f78aa..fbc6b591d8 100644 --- a/docs/components/overview.mdx +++ b/docs/components/overview.mdx @@ -5,15 +5,48 @@ description: A list of Clerk's comprehensive suite of components designed to sea Clerk offers a comprehensive suite of components designed to seamlessly integrate authentication and multi-tenancy into your application. With Clerk components, you can easily customize the appearance of authentication components and pages, manage the entire authentication flow to suit your specific needs, and even build robust SaaS applications. -To get started, select a component from the navigation on the left. +## UI components -## What are control components? +- [``](/docs/components/authentication/sign-in) +- [``](/docs/components/authentication/sign-up) +- [``](/docs/components/authentication/google-one-tap) +- [``](/docs/components/user/user-button) +- [``](/docs/components/user/user-profile) +- [``](/docs/components/organization/create-organization) +- [``](/docs/components/organization/organization-profile) +- [``](/docs/components/organization/organization-switcher) +- [``](/docs/components/organization/organization-list) +- [``](/docs/components/waitlist) + +## Control components + +{/* TODO(Alexis): update with new callout */} Control components manage authentication-related behaviors in your application. They handle tasks such as controlling content visibility based on user authentication status, managing loading states during authentication processes, and redirecting users to appropriate pages. Control components render at `` and `` states for assertions on the [`Clerk` object](/docs/references/javascript/clerk/clerk). A common example is the [``](/docs/components/control/signed-in) component, which allows you to conditionally render content only when a user is authenticated. +- [``](/docs/components/control/authenticate-with-callback) +- [``](/docs/components/control/clerk-loaded) +- [``](/docs/components/control/clerk-loading) +- [``](/docs/components/protect) +- [``](/docs/components/control/multi-session) +- [``](/docs/components/control/redirect-to-signin) +- [``](/docs/components/control/redirect-to-signup) +- [``](/docs/components/control/redirect-to-userprofile) +- [``](/docs/components/control/redirect-to-organizationprofile) +- [``](/docs/components/control/redirect-to-createorganization) +- [``](/docs/components/control/signed-in) +- [``](/docs/components/control/signed-out) + +## Unstyled components + +- [``](/docs/components/unstyled/sign-in-button) +- [``](/docs/components/unstyled/sign-in-with-metamask) +- [``](/docs/components/unstyled/sign-up-button) +- [``](/docs/components/unstyled/sign-out-button) + ## Customization Guides -- [Theme components with the appearance prop](/docs/customization/overview) +- [Customize components with the `appearance` prop](/docs/customization/overview) - [Localize components with the `localization` prop (experimental)](/docs/customization/localization) - [Add pages to the `` component](/docs/customization/user-profile) - [Add pages to the `` component](/docs/customization/organization-profile) From ba1871eacb8dd3ac449facf668caca97f186d8fc Mon Sep 17 00:00:00 2001 From: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> Date: Thu, 12 Dec 2024 18:13:13 -0500 Subject: [PATCH 33/36] (chore) steps component now accepts h2s (#1801) --- CONTRIBUTING.md | 8 ++-- .../oidc/custom-provider.mdx | 14 +++---- .../enterprise-connections/saml/azure.mdx | 16 ++++---- .../saml/custom-provider.mdx | 12 +++--- .../enterprise-connections/saml/google.mdx | 22 +++++------ .../enterprise-connections/saml/okta.mdx | 16 ++++---- .../social-connections/spotify.mdx | 6 +-- .../social-connections/x-twitter.mdx | 12 +++--- .../making/custom-session-token.mdx | 8 ++-- docs/custom-flows/bot-sign-up-protection.mdx | 4 +- docs/custom-flows/email-password-mfa.mdx | 8 ++-- docs/custom-flows/email-password.mdx | 6 +-- docs/custom-flows/email-sms-otp.mdx | 8 ++-- docs/custom-flows/embedded-email-links.mdx | 4 +- docs/custom-flows/google-one-tap.mdx | 4 +- docs/custom-flows/manage-sms-based-mfa.mdx | 4 +- docs/custom-flows/manage-totp-based-mfa.mdx | 6 +-- .../customization/elements/guides/sign-in.mdx | 12 +++--- .../customization/elements/guides/sign-up.mdx | 12 +++--- docs/deployments/migrate-from-firebase.mdx | 22 +++++------ docs/guides/authjs-migration.mdx | 38 +++++++++---------- docs/guides/basic-rbac.mdx | 24 ++++++------ docs/guides/force-organizations.mdx | 18 ++++----- docs/guides/waitlist.mdx | 16 ++++---- docs/integrations/databases/convex.mdx | 18 ++++----- docs/integrations/databases/fauna.mdx | 10 ++--- docs/integrations/databases/firebase.mdx | 10 ++--- docs/integrations/databases/instantdb.mdx | 10 ++--- docs/integrations/databases/neon.mdx | 18 ++++----- docs/quickstarts/astro.mdx | 14 +++---- docs/quickstarts/chrome-extension.mdx | 26 ++++++------- docs/quickstarts/expo.mdx | 22 +++++------ docs/quickstarts/express.mdx | 8 ++-- docs/quickstarts/fastify.mdx | 10 ++--- docs/quickstarts/ios.mdx | 20 +++++----- docs/quickstarts/javascript.mdx | 20 +++++----- docs/quickstarts/nextjs.mdx | 10 ++--- docs/quickstarts/react-router.mdx | 10 ++--- docs/quickstarts/react.mdx | 14 +++---- docs/quickstarts/remix.mdx | 16 ++++---- docs/quickstarts/setup-clerk.mdx | 8 ++-- docs/quickstarts/tanstack-start.mdx | 16 ++++---- docs/references/astro/react.mdx | 12 +++--- .../chrome-extension/add-react-router.mdx | 10 ++--- .../references/chrome-extension/sync-host.mdx | 8 ++-- docs/references/expo/local-credentials.mdx | 10 ++--- .../custom-signup-signin-pages.mdx | 6 +-- docs/references/ios/sign-in-with-apple.mdx | 8 ++-- .../nextjs/custom-signup-signin-pages.mdx | 12 +++--- docs/references/nextjs/trpc.mdx | 10 ++--- .../nextjs/usage-with-older-versions.mdx | 4 +- .../custom-signup-signin-pages.mdx | 10 ++--- docs/references/react-router/library-mode.mdx | 8 ++-- docs/references/redwood/overview.mdx | 14 +++---- .../remix/custom-signup-signin-pages.mdx | 8 ++-- docs/references/remix/spa-mode.mdx | 12 +++--- docs/references/ruby/overview.mdx | 14 +++---- docs/testing/cypress/overview.mdx | 8 ++-- docs/testing/playwright/overview.mdx | 8 ++-- .../playwright/test-authenticated-flows.mdx | 10 ++--- docs/webhooks/loops.mdx | 8 ++-- docs/webhooks/sync-data.mdx | 22 +++++------ styleguides/SSO.STYLEGUIDE.MD | 2 +- 63 files changed, 371 insertions(+), 393 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4136a9f280..398002e105 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -439,18 +439,18 @@ console.log('ignored') ### `` -The `` component is used to number a set of instructions with an outcome. It uses the highest heading available in the component to denote each step. Can be used with `h3` headings. +The `` component is used to number a set of instructions with an outcome. It uses the highest heading available in the component to denote each step. Can be used with `h2` and `h3` headings. ```mdx -### Step 1 +## Step 1 Do these actions to complete Step 1. -### Another step +## Another step -#### A heading inside a step +### A heading inside a step Do these actions to complete Step 2. diff --git a/docs/authentication/enterprise-connections/oidc/custom-provider.mdx b/docs/authentication/enterprise-connections/oidc/custom-provider.mdx index 3ae5b0ce3f..ffe342ec81 100644 --- a/docs/authentication/enterprise-connections/oidc/custom-provider.mdx +++ b/docs/authentication/enterprise-connections/oidc/custom-provider.mdx @@ -25,7 +25,7 @@ This guide explains how to use a custom [OpenID Connect (OIDC)](https://openid.n To make the setup process easier, it's recommended to keep two browser tabs open: one for the [Clerk Dashboard](https://dashboard.clerk.com/last-active?path=user-authentication/sso-connections) and one for your Identity Provider (IdP). - ### Set up an enterprise connection in Clerk + ## Set up an enterprise connection in Clerk 1. In the Clerk Dashboard, navigate to the [**SSO Connections**](https://dashboard.clerk.com/last-active?path=user-authentication/sso-connections) page. 1. Select **Add connection** and select **For specific domains**. @@ -35,14 +35,14 @@ To make the setup process easier, it's recommended to keep two browser tabs open 1. Add the **Specific Domain** that you want to allow this connection for. This is the domain of the users you want to allow to sign in to your app. 1. Select **Add connection**. You will be redirected to the connection's configuration page. Keep this page open. - ### Configure your IdP + ## Configure your IdP 1. If necessary, create a new application in your IdP. 1. In the connection's configuration page of the Clerk Dashboard, copy the **Authorized redirect URI**. 1. Add the value to your IdP's whitelisted URLs. 1. Find your application's **Discovery Endpoint**, **Client ID**, and **Client Secret** and copy them. - ### Set the Discovery Endpoint, Client ID, and Client Secret in Clerk + ## Set the Discovery Endpoint, Client ID, and Client Secret in Clerk 1. In your IdP settings, copy your application's **Discovery Endpoint**, **Client ID**, and **Client Secret**. 1. In the connection's configuration page in the Clerk Dashboard, paste these values in their respective fields. @@ -52,7 +52,7 @@ To make the setup process easier, it's recommended to keep two browser tabs open > [!NOTE] > Most IdPs provide a **Discovery Endpoint** to retrieve metadata about an OIDC provider. If your IdP doesn't offer this endpoint or if you need greater control over the setup process, in the connection's configuration page in the Clerk Dashboard, find the **Identity Provider Configuration** section and select **Use Manual Configuration** to manually configure the connection. - ### Configure attribute mapping (optional) + ## Configure attribute mapping (optional) Clerk expects the claims returned by your IdP to follow the [OIDC Standard](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims). If your provider returns claims in a non-standard format, use the **Attribute Mapping** section on the connection's configuration page to adjust the mapping of Clerk's user properties to match the IdP's claim attributes. @@ -61,7 +61,7 @@ To make the setup process easier, it's recommended to keep two browser tabs open > > If the IdP doesn't return this claim, you can leave the **Email address verified** field blank and set the **Default value** to **True**. This should only be done if you fully trust the IdP, as it can expose your app to [OAuth attacks](https://www.descope.com/blog/post/noauth). - ### Allow additional identifiers (optional) + ## Allow additional identifiers (optional) User profile information is sourced from the IdP. To allow users to add new identifiers (e.g., email address or phone number) to their profiles: @@ -69,14 +69,14 @@ To make the setup process easier, it's recommended to keep two browser tabs open 1. Enable **Allow additional identifiers**. 1. Select **Save**. - ### Enable the connection for Clerk + ## Enable the connection for Clerk To make the connection available for your users to authenticate with: 1. Navigate back to the Clerk Dashboard where you should still have the connection's configuration page open. If not, navigate to the [**SSO connections**](https://dashboard.clerk.com/last-active?path=user-authentication/sso-connections) page and select the connection. 1. At the top of the page, toggle on **Enable connection** and select **Save**. - ### Test your connection + ## Test your connection The simplest way to test your enterprise connection is to visit your Clerk app's [Account Portal](/docs/customization/account-portal/overview), which is available for all Clerk apps out-of-the-box. diff --git a/docs/authentication/enterprise-connections/saml/azure.mdx b/docs/authentication/enterprise-connections/saml/azure.mdx index 87a7039fc4..67a08b2cbd 100644 --- a/docs/authentication/enterprise-connections/saml/azure.mdx +++ b/docs/authentication/enterprise-connections/saml/azure.mdx @@ -25,7 +25,7 @@ Enabling single sign-on (SSO) with **Microsoft Azure Entra ID** (formerly [Activ To make the setup process easier, it's recommended to keep two browser tabs open: one for the [Clerk Dashboard](https://dashboard.clerk.com/last-active?path=user-authentication/sso-connections) and one for your [Microsoft Azure portal](https://portal.azure.com). - ### Set up an enterprise connection in Clerk + ## Set up an enterprise connection in Clerk To create a SAML connection in Clerk: @@ -38,7 +38,7 @@ To make the setup process easier, it's recommended to keep two browser tabs open 1. Find the **Service Provider Configuration** section. 1. Save the **Identifier (Entity ID)** and **Reply URL (Assertion Consumer Service URL)** values somewhere secure. You'll need these in the [Configure your service provider](#configure-your-service-provider) step. Leave this page open. - ### Create a new enterprise app in Microsoft + ## Create a new enterprise app in Microsoft To create a new enterprise app in Microsoft: @@ -52,7 +52,7 @@ To make the setup process easier, it's recommended to keep two browser tabs open - Ensure the option **Integrate any other application you don't find in the gallery (Non-gallery)** is selected. - Select **Create**. - ### Assign selected user or group in Microsoft + ## Assign selected user or group in Microsoft Now that you have created the enterprise app, you need to assign users or groups to the app. For example, if you were part of the Clerk organization, you would have access to users and groups within the Clerk organization. In this case, you could assign individual users or entire groups to the enterprise app you just created. @@ -63,14 +63,14 @@ To make the setup process easier, it's recommended to keep two browser tabs open 1. Select **Select** at the bottom of the page. You'll be redirected to the **Add Assignment** page. 1. Select **Assign** at the bottom of the page. - ### Configure SSO in Microsoft + ## Configure SSO in Microsoft After assigning the user or group to the enterprise app, you need to configure the SSO settings to enable SAML SSO. 1. In the navigation sidebar, open the **Manage** dropdown and select **Single sign-on**. 1. In the **Select a single sign-on method** section, select **SAML**. - ### Configure your service provider + ## Configure your service provider To configure Clerk as your service provider, add these two fields to your IdP's application: @@ -84,7 +84,7 @@ To make the setup process easier, it's recommended to keep two browser tabs open 1. Paste the **Identifier (Entity ID)** and **Reply URL (Assertion Consumer Service URL)** values you saved earlier into their respective fields. These values will be saved automatically. 1. Select **Save** at the top of the panel. Close the panel. - ### Configure your identity provider + ## Configure your identity provider To configure Microsoft Entra ID as your identity provider, add the following fields to your app: @@ -93,7 +93,7 @@ To make the setup process easier, it's recommended to keep two browser tabs open 1. Navigate back to the **Clerk Dashboard**. In the **Identity Provider Configuration** section, under **App Federation Metadata Url**, paste the **App Federation Metadata URL**. 1. Select **Fetch & save**. - ### Map Microsoft claims to Clerk attributes + ## Map Microsoft claims to Clerk attributes Mapping the claims in your IdP to the attributes in Clerk ensures that the data from your IdP is correctly mapped to the data in Clerk. @@ -112,7 +112,7 @@ To make the setup process easier, it's recommended to keep two browser tabs open 1. Next to **Source attribute**, search for and select `user.userprincipalname` in the dropdown. 1. Select **Save** at the top of the page. - ### Enable the connection for Clerk + ## Enable the connection for Clerk To make the connection available for your users to authenticate with: diff --git a/docs/authentication/enterprise-connections/saml/custom-provider.mdx b/docs/authentication/enterprise-connections/saml/custom-provider.mdx index b717cfa88e..e0dbd4a0d6 100644 --- a/docs/authentication/enterprise-connections/saml/custom-provider.mdx +++ b/docs/authentication/enterprise-connections/saml/custom-provider.mdx @@ -22,10 +22,8 @@ description: Learn how to integrate an Identity Provider with Clerk using SAML S Clerk supports Enterprise SSO via the SAML protocol, enabling you to create authentication strategies for an Identity Provider (IdP). Currently, Clerk offers direct integrations with [Microsoft Azure AD](/docs/authentication/enterprise-connections/saml/azure), [Google Workspace](/docs/authentication/enterprise-connections/saml/google), and [Okta Workforce](/docs/authentication/enterprise-connections/saml/okta) as IdPs. However, you can also integrate with any other IdP that supports the SAML protocol. This guide will show you how to set up a SAML connection with a custom IdP in Clerk. -## Tutorial - - ### Set up an enterprise connection in Clerk + ## Set up an enterprise connection in Clerk To create a SAML connection in Clerk: @@ -36,23 +34,23 @@ Clerk supports Enterprise SSO via the SAML protocol, enabling you to create auth 1. Add the **Specific Domain** that you want to allow this connection for. This is the domain of the users you want to allow to sign in to your application. 1. Select **Add connection**. You will be redirected to the connection's configuration page. - ### Create a new enterprise application in your IdP + ## Create a new enterprise application in your IdP Create a new application in your IdP. In the next steps, you'll configure your IdP with the settings provided by your Service Provider (Clerk), and configure Clerk with the settings provided by your IdP. Keep both the IdP and Clerk Dashboard open. - ### Configure your Identity Provider + ## Configure your Identity Provider There are two options for configuring your IdP: - [**Metadata configuration**](#metadata-configuration) - This is where you can download your IdP's metadata file or input the metadata URL that you got from your IdP. This is the recommended way to configure your IdP, but not all IdPs support this method. - [**Custom configuration**](#custom-configuration) - This is where you can manually input the configuration settings for your IdP. - #### Metadata configuration + ### Metadata configuration 1. In your IdP dashboard, find where you can download the metadata file or copy the metadata URL. 1. In the Clerk Dashboard on the connection's configuration page, under **Identity Provider Configuration**,select **Add via metadata**. Input the metadata URL or upload the metadata file that you got from your IdP. - #### Custom configuration + ### Custom configuration If you choose to manually input the configuration settings for your IdP, you will need to fill these three fields in the Clerk Dashboard: diff --git a/docs/authentication/enterprise-connections/saml/google.mdx b/docs/authentication/enterprise-connections/saml/google.mdx index 010d286a92..4ec7423f1c 100644 --- a/docs/authentication/enterprise-connections/saml/google.mdx +++ b/docs/authentication/enterprise-connections/saml/google.mdx @@ -20,10 +20,8 @@ description: Learn how to integrate Google Workspace with Clerk using SAML SSO. - Use Google Workspace to enable single sign-on (SSO) via SAML for your Clerk application. -## Tutorial - - ### Set up an enterprise connection in Clerk + ## Set up an enterprise connection in Clerk To create a SAML connection in Clerk: @@ -34,7 +32,7 @@ description: Learn how to integrate Google Workspace with Clerk using SAML SSO. 1. Add the **Specific Domain** that you want to allow this connection for. This is the domain of the users you want to allow to sign in to your application. 1. Select **Add connection**. You'll be redirected to the connection's configuration page. - ### Create a new enterprise application in Google + ## Create a new enterprise application in Google To create a new enterprise application in Google: @@ -45,20 +43,20 @@ description: Learn how to integrate Google Workspace with Clerk using SAML SSO. 1. In the **App details** section, an **App name** is required. 1. Select the **Continue** button. - ### Configure your identity provider + ## Configure your identity provider There are two options for configuring your IdP: - [**Metadata configuration**](#metadata-configuration) - This is where you can input the URL to your IdP's metadata file. This is the recommended way to configure your IdP. - [**Custom configuration**](#custom-configuration) - This is where you can manually input the configuration settings for your IdP. - #### Metadata configuration + ### Metadata configuration 1. In the Google Admin Console, under **Option 1: Download IdP Metadata**, select the **Download Metadata** button. 1. Navigate back to the Clerk Dashboard and in the **Identity Provider Configuration** section, select the **Upload file** button. 1. Upload the metadata file you downloaded from Google. - #### Custom configuration + ### Custom configuration If you choose to manually input the configuration settings for your IdP, you must add these three fields to your Clerk settings: @@ -71,7 +69,7 @@ description: Learn how to integrate Google Workspace with Clerk using SAML SSO. 1. Fill in the **SSO URL**, **Entity ID**, and upload the **Certificate**. Don't forget to select **Save**. 1. In the Google Admin Console, select the **Continue** button. - ### Configure your service provider + ## Configure your service provider To configure your service provider (Clerk), you will need to add these two fields to your IdP's application: @@ -85,7 +83,7 @@ description: Learn how to integrate Google Workspace with Clerk using SAML SSO. 1. In the Google Admin Console, paste these values into their respective fields. 1. Under the **Name ID** section, select the dropdown for **Name ID format** and select **Email**. - ### Map Google claims to Clerk attributes + ## Map Google claims to Clerk attributes Mapping the claims in your IdP to the attributes in Clerk ensures that the data from your IdP is correctly mapped to the data in Clerk. @@ -103,7 +101,7 @@ description: Learn how to integrate Google Workspace with Clerk using SAML SSO. 1. Enter `mail` in the field. 1. If you have additional claims that you would like to map to Clerk, you can do so by following the steps in the [Map other claims](#map-other-claims-optional) section. Otherwise, select the **Finish** button. - #### Map other claims (optional) + ### Map other claims (optional) In Clerk, the [`User`](/docs/users/overview#user-object) object has a `publicMetadata` property that you can use to store additional information about your users. @@ -121,7 +119,7 @@ description: Learn how to integrate Google Workspace with Clerk using SAML SSO. Learn more about [how to access the metadata from our APIs](/docs/users/metadata). - ### Enable the connection on Google + ## Enable the connection on Google Once the configuration is complete, you will be redirected to the app details page. @@ -129,7 +127,7 @@ description: Learn how to integrate Google Workspace with Clerk using SAML SSO. 1. In the **Service status** section, select **ON for everyone**. 1. Select the **Save** button. - ### Enable the connection for Clerk + ## Enable the connection for Clerk To make the connection available for your users to authenticate with: diff --git a/docs/authentication/enterprise-connections/saml/okta.mdx b/docs/authentication/enterprise-connections/saml/okta.mdx index f530a92eae..2ba9589b4c 100644 --- a/docs/authentication/enterprise-connections/saml/okta.mdx +++ b/docs/authentication/enterprise-connections/saml/okta.mdx @@ -20,10 +20,8 @@ description: Learn how to integrate Okta Workforce with Clerk using SAML SSO. - Use Okta Workforce to enable single sign-on (SSO) via SAML for your Clerk application. -## Tutorial - - ### Set up an enterprise connection in Clerk + ## Set up an enterprise connection in Clerk To create a SAML connection in Clerk: @@ -37,7 +35,7 @@ description: Learn how to integrate Okta Workforce with Clerk using SAML SSO. 1. Save the **Single sign-on URL** and the **Audience URI (SP Entity ID)** values somewhere secure. You'll need these in the [Configure your service provider](#configure-your-service-provider) step. 1. Leave this page open. - ### Create a new enterprise application in Okta + ## Create a new enterprise application in Okta To create a new enterprise application in Okta: @@ -49,7 +47,7 @@ description: Learn how to integrate Okta Workforce with Clerk using SAML SSO. 1. Once redirected to the **Create SAML Integration** page, fill in the **General Settings** fields. An **App name** is required. 1. Select the **Next** button to continue. - ### Configure your service provider + ## Configure your service provider Once you have moved forward from the **General Settings** instructions, you will be presented with the **Configure SAML** page. @@ -62,7 +60,7 @@ description: Learn how to integrate Okta Workforce with Clerk using SAML SSO. 1. Paste the **Single sign-on URL** and the **Audience URI (SP Entity ID)** values that you saved earlier into their respective fields. - ### Map Okta claims to Clerk attributes + ## Map Okta claims to Clerk attributes Mapping the claims in your IdP to the attributes in Clerk ensures that the data from your IdP is correctly mapped to the data in Clerk. @@ -84,7 +82,7 @@ description: Learn how to integrate Okta Workforce with Clerk using SAML SSO. 1. Scroll to the bottom of the page and select the **Next** button to continue. 1. You will be redirected to the **Feedback** page. Fill out the feedback however you would like and select the **Finish** button to complete the setup. - ### Assign selected user or group in Okta + ## Assign selected user or group in Okta You need to assign your users/user groups to your enterprise application. For example, if you were part of the Clerk organization, you would have access to users and groups in the Clerk organization. In this case, you could assign one or more users or entire groups to the enterprise application you just created. @@ -94,7 +92,7 @@ description: Learn how to integrate Okta Workforce with Clerk using SAML SSO. 1. Select the **Assign** button next to the user or group that you want to assign. 1. Select the **Done** button to complete the assignment. - ### Configure your identity provider + ## Configure your identity provider Once you have completed the setup in Okta, you will be redirected to the application instances page with the **Sign On** tab selected. @@ -103,7 +101,7 @@ description: Learn how to integrate Okta Workforce with Clerk using SAML SSO. 1. Under the **Metadata configuration** option, paste the **Metadata URL**. 1. Select the **Fetch & save** button to complete the setup. - ### Enable the connection for Clerk + ## Enable the connection for Clerk To make the connection available for your users to authenticate with: diff --git a/docs/authentication/social-connections/spotify.mdx b/docs/authentication/social-connections/spotify.mdx index 14bf02bde1..93023f25ab 100644 --- a/docs/authentication/social-connections/spotify.mdx +++ b/docs/authentication/social-connections/spotify.mdx @@ -28,7 +28,7 @@ Enabling OAuth with [Spotify](https://developer.spotify.com/documentation/web-ap To make the setup process easier, it's recommended to keep two browser tabs open: one for the [Clerk Dashboard](https://dashboard.clerk.com/last-active?path=user-authentication/sso-connections) and one for your [Spotify Developer Dashboard](https://developer.spotify.com/). - ### Enable Spotify as a social connection in Clerk + ## Enable Spotify as a social connection in Clerk 1. In the Clerk Dashboard, navigate to the [**SSO connections**](https://dashboard.clerk.com/last-active?path=user-authentication/sso-connections) page. 1. Select **Add connection** and select **For all users**. @@ -36,7 +36,7 @@ To make the setup process easier, it's recommended to keep two browser tabs open 1. Ensure that both **Enable for sign-up and sign-in** and **Use custom credentials** are toggled on. 1. Save the **Redirect URI** somewhere secure. Keep the modal and page open. - ### Create your app in Spotify + ## Create your app in Spotify 1. On a separate page, go to the [Spotify Developer Dashboard](https://developer.spotify.com/) and sign in. 1. In the top-right, select your profile button and select [**Dashboard**](https://developer.spotify.com/dashboard). @@ -45,7 +45,7 @@ To make the setup process easier, it's recommended to keep two browser tabs open 1. Select **Save**. 1. On your app page, select **Settings**. Keep this page open. - ### Set the Client ID and Client Secret in the Clerk Dashboard + ## Set the Client ID and Client Secret in the Clerk Dashboard 1. In the Spotify app's settings page, save the **Client ID** and **Client secret** somewhere secure. To reveal the **Client secret**, you must select **View client secret**. 1. Navigate back to the Clerk Dashboard where the modal should still be open and paste these values into the respective fields. diff --git a/docs/authentication/social-connections/x-twitter.mdx b/docs/authentication/social-connections/x-twitter.mdx index 296986e1c3..4610f5a6d9 100644 --- a/docs/authentication/social-connections/x-twitter.mdx +++ b/docs/authentication/social-connections/x-twitter.mdx @@ -23,15 +23,13 @@ description: Learn how to set up a social connection with X/Twitter v2 in your C - Set X/Twitter's **Client ID** and **Client Secret** in the Clerk Dashboard -## Overview - Clerk does not currently support preconfigured shared OAuth credentials for X/Twitter on development instances. This means you will have to provide custom credentials for both development _and_ production instances, which involves generating your own **Client ID** and **Client Secret** using your X/Twitter Developer account. This tutorial will walk you through that process in just a few simple steps. > [!WARNING] > X/Twitter v2 is currently not providing email addresses of users. The user will have to fill in their email address manually when they return to your application after authenticating with X/Twitter. - ### Create an X/Twitter application + ## Create an X/Twitter application If you don't have an existing X/Twitter application you've set up for social connection, you need to register a new one at the [X/Twitter Developer Portal](https://developer.twitter.com/en/portal/dashboard). Note that the process requires approval from X/Twitter before your new application can be used. @@ -40,7 +38,7 @@ Clerk does not currently support preconfigured shared OAuth credentials for X/Tw 1. Navigate to the X/Twitter Developer Portal and go to [**Projects & Apps**](https://developer.twitter.com/en/portal/projects-and-apps). 1. Select **+ Add App**. After entering a name, you will be presented with your app's credentials. However, for setting up the X/Twitter v2 social connection with Clerk, **you won't need these credentials**. This is because you will be utilizing the OAuth 2.0 flow, which relies on different authentication details. - ### Enable X/Twitter as a social connection + ## Enable X/Twitter as a social connection To enable X/Twitter as a social connection for your Clerk application: @@ -49,7 +47,7 @@ Clerk does not currently support preconfigured shared OAuth credentials for X/Tw 1. In the **Choose provider** dropdown, select **X/Twitter**. 1. Toggle on **Use custom credentials** and copy **Redirect URI**. Keep this modal and page open. - ### Set the Redirect URI in your X/Twitter application + ## Set the Redirect URI in your X/Twitter application 1. Navigate back to the X/Twitter Developer portal. 1. On the application settings screen, scroll down to the **User authentication settings** section and select **Set up**. You'll be presented with the **User authentication settings** page. @@ -58,7 +56,7 @@ Clerk does not currently support preconfigured shared OAuth credentials for X/Tw 1. Under **App info**, in the **Callback URI / Redirect URL** input, paste the **Redirect URI** value you copied from the Clerk Dashboard. 1. Fill any other required fields, such as the **Website URL**, and select **Save**. - ### Set the Client ID and Client Secret in the Clerk Dashboard + ## Set the Client ID and Client Secret in the Clerk Dashboard After setting up your X/Twitter application, you should be able to copy your **Client ID** and **Client Secret**. @@ -67,7 +65,7 @@ Clerk does not currently support preconfigured shared OAuth credentials for X/Tw > [!NOTE] > If the modal or page is not still open, in the Clerk Dashboard, navigate to the [**SSO connections**](https://dashboard.clerk.com/last-active?path=user-authentication/sso-connections) page. Next to **X/Twitter**, select the settings icon. Under **Use custom credentials**, you can paste the **Client ID** and **Client Secret** into their respective fields. - ### Test your OAuth + ## Test your OAuth The simplest way to test your OAuth is to visit your Clerk application's [Account Portal](/docs/customization/account-portal/overview), which is available for all Clerk applications out-of-the-box. diff --git a/docs/backend-requests/making/custom-session-token.mdx b/docs/backend-requests/making/custom-session-token.mdx index ee28e7e925..4b4973f87e 100644 --- a/docs/backend-requests/making/custom-session-token.mdx +++ b/docs/backend-requests/making/custom-session-token.mdx @@ -11,10 +11,8 @@ This guide will show you how to customize a session token to include additional -{/* TODO: Update the H3 to an H2 when the Steps component can accept headings other than H3. */} - - ### Add custom claims to your session token + ## Add custom claims to your session token 1. In the Clerk Dashboard, navigate to the [**Sessions**](https://dashboard.clerk.com/last-active?path=sessions) page. 1. In the **Customize your session token** section, click the **Edit** button. @@ -24,7 +22,7 @@ This guide will show you how to customize a session token to include additional ![Clerk Dashboard showing the custom claim modal](/docs/images/advance/session-tokens/custom-session-example.png) - ### Use the custom claims in your application + ## Use the custom claims in your application The [`Auth`](/docs/references/nextjs/auth-object) object in the `@clerk/nextjs` package includes a `sessionClaims` property that contains the custom claims you added to your session token. @@ -64,7 +62,7 @@ This guide will show you how to customize a session token to include additional ``` - ### Add global TypeScript type for custom session claims + ## Add global TypeScript type for custom session claims To get auto-complete and prevent TypeScript errors when working with custom session claims, you can define a global type. diff --git a/docs/custom-flows/bot-sign-up-protection.mdx b/docs/custom-flows/bot-sign-up-protection.mdx index 20bf49b4cc..e6c63a18b5 100644 --- a/docs/custom-flows/bot-sign-up-protection.mdx +++ b/docs/custom-flows/bot-sign-up-protection.mdx @@ -8,12 +8,12 @@ description: Learn how to add Clerk's bot protection to your custom sign-up flow Clerk provides the ability to add a CAPTCHA widget to your sign-up flows to protect against bot sign-ups. The [``](/docs/components/authentication/sign-up) component handles this flow out-of-the-box. However, if you're building a custom user interface, this guide will show you how to add the CAPTCHA widget to your custom sign-up flow. - ### Enable bot sign-up protection + ## Enable bot sign-up protection 1. In the Clerk Dashboard, navigate to the [**Attack protection**](https://dashboard.clerk.com/last-active?path=user-authentication/attack-protection) page. 1. In the **Bot sign-up protection** section, enable the feature and choose the **CAPTCHA type** you want to use. - ### Add the CAPTCHA widget to your custom sign-up form + ## Add the CAPTCHA widget to your custom sign-up form To render the CAPTCHA widget in your custom sign-up form, you need to include a specific element in your DOM. Specifically, there should be a `
` element by the time you call `signUp.create()`. This element acts as a placeholder onto which the widget will be rendered. diff --git a/docs/custom-flows/email-password-mfa.mdx b/docs/custom-flows/email-password-mfa.mdx index d4861d8c4a..2296237854 100644 --- a/docs/custom-flows/email-password-mfa.mdx +++ b/docs/custom-flows/email-password-mfa.mdx @@ -11,10 +11,8 @@ Clerk supports second factor verification through **SMS verification code**, **A This guide will walk you through how to build a custom email/password sign-in flow that supports **Authenticator application** and **Backup codes** as the second factor. -{/* TODO: Update these Steps when the Steps component can accept other headings. As of right now, Steps can only accept H3s. */} - - ### Enable email and password authentication + ## Enable email and password authentication This example uses email and password authentication, however, you can modify this approach according to the needs of your application. To use email and password authentication, you first need to enable these authentication strategies in the Clerk Dashboard. @@ -22,7 +20,7 @@ This guide will walk you through how to build a custom email/password sign-in fl 1. Ensure that _only_ **Email address** is required. If **Phone number** and **Username** are enabled, ensure they are not required. Use the settings icon next to each user attribute to check if a setting is required or optional. If you want to require **Username**, you must collect the username and pass the data to the `create()` method in your custom flow. 1. In the **Authentication strategies** section of this page, ensure **Password** is enabled. - ### Enable multi-factor authentication + ## Enable multi-factor authentication For your users to be able to enable MFA for their account, you need to enable MFA as an authentication strategy in your Clerk application. @@ -30,7 +28,7 @@ This guide will walk you through how to build a custom email/password sign-in fl 1. For the purpose of this guide, toggle on both the **Authenticator application** and **Backup codes** strategies. 1. Select **Save**. - ### Sign-in flow + ## Sign-in flow Signing in to an MFA-enabled account is identical to the regular sign-in process. However, in the case of an MFA-enabled account, a sign-in won't convert until both first factor and second factor verifications are completed. diff --git a/docs/custom-flows/email-password.mdx b/docs/custom-flows/email-password.mdx index 91d7f95dda..d22ac988ff 100644 --- a/docs/custom-flows/email-password.mdx +++ b/docs/custom-flows/email-password.mdx @@ -10,7 +10,7 @@ This guide will walk you through how to build a custom email/password sign-up an {/* TODO: Update these Steps when the Steps component can accept other headings. As of right now, Steps can only accept H3s. */} - ### Enable email and password authentication + ## Enable email and password authentication To use email and password authentication, you first need to enable these [authentication strategies](/docs/authentication/configuration/sign-up-sign-in-options#authentication-strategies) in the Clerk Dashboard. @@ -21,7 +21,7 @@ This guide will walk you through how to build a custom email/password sign-up an > [!NOTE] > By default, the [verification method](/docs/authentication/configuration/sign-up-sign-in-options#verification-methods) for the **Email address** strategy is set to **Email verification code**. This means that when a user signs up using their email address and password, Clerk sends a one-time code to their email address. The user must then enter this code to verify their email and complete the sign-up process. - ### Sign-up flow + ## Sign-up flow To sign up a user using their email, password, and email verification code, you must: @@ -467,7 +467,7 @@ This guide will walk you through how to build a custom email/password sign-up an - ### Sign-in flow + ## Sign-in flow To authenticate a user using their email and password, you must: diff --git a/docs/custom-flows/email-sms-otp.mdx b/docs/custom-flows/email-sms-otp.mdx index 363d863d34..9eaec44650 100644 --- a/docs/custom-flows/email-sms-otp.mdx +++ b/docs/custom-flows/email-sms-otp.mdx @@ -9,10 +9,8 @@ Clerk supports passwordless authentication, which lets users sign in and sign up This guide will walk you through how to build a custom SMS OTP sign-up and sign-in flow. The process for using email OTP is similar, and the differences will be highlighted throughout. -{/* TODO: Update these Steps when the Steps component can accept other headings. As of right now, Steps can only accept H3s. */} - - ### Enable SMS OTP + ## Enable SMS OTP To use SMS OTP as an authentication strategy, you first need to enable it in the Clerk Dashboard. @@ -20,7 +18,7 @@ This guide will walk you through how to build a custom SMS OTP sign-up and sign- 1. Ensure that _only_ **Phone number** is required. If **Email address** or **Username** are enabled, ensure they are not required. Use the settings icon to check if a setting is required or optional. If you would like to require **Username**, you must collect the username and pass it to the `create()` method in your custom flow. For this guide, if you would like to use email OTP instead, require the **Email address** option instead of the **Phone number** option. 1. In the **Authentication strategies** section of this page, ensure **SMS verification code** is enabled. Ensure **Password** is toggled off, as you are prioritizing passwordless, SMS OTP-only authentication in this guide. If you would like to use email OTP instead, enable the **Email verification code** strategy instead of the **SMS verification code** strategy. - ### Sign-up flow + ## Sign-up flow To sign up a user using an OTP, you must: @@ -306,7 +304,7 @@ This guide will walk you through how to build a custom SMS OTP sign-up and sign- To create a sign-up flow for email OTP, use the [`prepareEmailAddressVerification`](/docs/references/javascript/sign-up/email-verification#prepare-email-address-verification) and [`attemptEmailAddressVerification`](/docs/references/javascript/sign-up/email-verification#attempt-email-address-verification). These helpers work the same way as their phone number counterparts do in the previous example. You can find all available methods in the [`SignUp`](/docs/references/javascript/sign-in/sign-in) object documentation. - ### Sign-in flow + ## Sign-in flow To authenticate a user with an OTP, you must: diff --git a/docs/custom-flows/embedded-email-links.mdx b/docs/custom-flows/embedded-email-links.mdx index a7c6a6a6e9..2af4535257 100644 --- a/docs/custom-flows/embedded-email-links.mdx +++ b/docs/custom-flows/embedded-email-links.mdx @@ -15,7 +15,7 @@ Common use cases include: This guide will demonstrate how to generate a sign-in token and use it to sign in a user. - ### Generate a sign-in token + ## Generate a sign-in token [Sign-in tokens](/docs/reference/backend-api/tag/Sign-in-Tokens#operation/CreateSignInToken){{ target: '_blank' }} are JWTs that can be used to sign in to an application without specifying any credentials. A sign-in token can be used **once**, and can be consumed from the Frontend API using the [`ticket`](/docs/references/javascript/sign-in/sign-in#sign-in-create-params) strategy, which is demonstrated in the following example. @@ -40,7 +40,7 @@ This guide will demonstrate how to generate a sign-in token and use it to sign i Then, you can embed this link anywhere, such as an email. - ### Build a custom flow for signing in with a sign-in token + ## Build a custom flow for signing in with a sign-in token To handle email links with sign-in tokens, you must set up a page in your frontend that detects the token, signs the user in, and performs any additional actions you need. diff --git a/docs/custom-flows/google-one-tap.mdx b/docs/custom-flows/google-one-tap.mdx index 0023351877..d072ead81d 100644 --- a/docs/custom-flows/google-one-tap.mdx +++ b/docs/custom-flows/google-one-tap.mdx @@ -10,11 +10,11 @@ description: Learn how to build a custom Google One Tap authentication flow usin This guide will walk you through how to build a custom Google One Tap authentication flow. - ### Enable Google as a social connection + ## Enable Google as a social connection To use Google One Tap with Clerk, follow the steps in the [dedicated guide](/docs/authentication/social-connections/google#configuring-google-social-connection) to configure Google as a social connection in the Clerk Dashboard using custom credentials. - ### Create the Google One Tap authentication flow + ## Create the Google One Tap authentication flow To authenticate users with Google One Tap, you must: diff --git a/docs/custom-flows/manage-sms-based-mfa.mdx b/docs/custom-flows/manage-sms-based-mfa.mdx index a16224c6fa..34d75f7092 100644 --- a/docs/custom-flows/manage-sms-based-mfa.mdx +++ b/docs/custom-flows/manage-sms-based-mfa.mdx @@ -13,14 +13,14 @@ One of the options that Clerk supports for MFA is **SMS verification codes**. Th > To learn how to build a custom flow for managing authenticator app (TOTP) MFA, see the [dedicated guide](/docs/custom-flows/manage-totp-based-mfa). - ### Enable multi-factor authentication + ## Enable multi-factor authentication For your users to be able to enable MFA for their account, you need to enable MFA as an MFA authentication strategy in your Clerk application. 1. In the Clerk Dashboard, navigate to the [**Multi-factor**](https://dashboard.clerk.com/last-active?path=user-authentication/multi-factor) page. 1. Enable **SMS verification code** and **Backup codes** and select **Save**. - ### Create the multi-factor management flow + ## Create the multi-factor management flow This example is written for Next.js App Router but it can be adapted for any React meta framework, such as Remix. diff --git a/docs/custom-flows/manage-totp-based-mfa.mdx b/docs/custom-flows/manage-totp-based-mfa.mdx index 62fee0ab1a..9710cfe585 100644 --- a/docs/custom-flows/manage-totp-based-mfa.mdx +++ b/docs/custom-flows/manage-totp-based-mfa.mdx @@ -13,7 +13,7 @@ One of the options that Clerk supports for MFA is **Authenticator applications ( > To learn how to build a custom flow for managing SMS MFA, see the [dedicated guide](/docs/custom-flows/manage-sms-based-mfa). - ### Enable multi-factor authentication + ## Enable multi-factor authentication For your users to be able to enable MFA for their account, you need to enable MFA as an MFA authentication strategy in your Clerk application. @@ -21,7 +21,7 @@ One of the options that Clerk supports for MFA is **Authenticator applications ( 1. Enable **Authenticator application** and **Backup codes**. 1. Select **Save**. - ### Create the multi-factor management flow + ## Create the multi-factor management flow @@ -306,7 +306,7 @@ One of the options that Clerk supports for MFA is **Authenticator applications ( - #### Force MFA (optional) + ### Force MFA (optional) While Clerk does not natively enforce MFA for all users, you can implement this functionality by using `clerkMiddleware()` to check whether a user has MFA enabled. diff --git a/docs/customization/elements/guides/sign-in.mdx b/docs/customization/elements/guides/sign-in.mdx index a2d83b1440..003a318b7d 100644 --- a/docs/customization/elements/guides/sign-in.mdx +++ b/docs/customization/elements/guides/sign-in.mdx @@ -34,7 +34,7 @@ description: Learn how to build a complete sign-in form with Clerk Elements. > - Clerk Elements currently only works with Next.js App Router and [Clerk Core 2](/changelog/2024-04-19){{ target: '_blank' }}. As it gets closer to a stable release, support for additional frameworks will be added. - ### Add a sign-in route + ## Add a sign-in route Create a new route in your Next.js application. The route needs to be an [optional catch-all route](https://nextjs.org/docs/pages/building-your-application/routing/dynamic-routes#optional-catch-all-segments) so the sign-in flow can handled nested paths, as shown in the following example: @@ -54,7 +54,7 @@ description: Learn how to build a complete sign-in form with Clerk Elements. > [!TIP] > If you're getting TypeScript errors on the `@clerk/elements` imports you probably have forgotten to set your [`moduleResolution`](https://www.typescriptlang.org/tsconfig/#moduleResolution) in `tsconfig.json` to `bundler`. - ### Add the start step + ## Add the start step The Clerk authentication flows are made up of **steps**. Steps handle rendering the UI for each part of the flow. To allow users to create a sign-in attempt, the `start` step needs to be rendered. The following example does so with the `` component: @@ -75,7 +75,7 @@ description: Learn how to build a complete sign-in form with Clerk Elements. } ``` - ### Add form fields + ## Add form fields Make it functional by adding input fields. The following example uses the `` component to render an `identifier` field, as well as the `` component to allow users to sign in with a social connection, like Google: @@ -111,7 +111,7 @@ description: Learn how to build a complete sign-in form with Clerk Elements. > [!NOTE] > If your Clerk instance supports signing in with Google and doesn't require multi-factor authentication (MFA), you should be able to complete a sign-in with the components rendered so far. - ### Add verification + ## Add verification As users progress through a sign-in attempt, they may be asked to **verify** a number of authentication factors in the `verifications` step. You can render a form for the user to complete verification, but each [verification strategy](/docs/customization/elements/reference/sign-in#strategy) requires different fields. You must render the form fields conditionally for each authentication strategy your instance supports using the `` component. @@ -163,7 +163,7 @@ description: Learn how to build a complete sign-in form with Clerk Elements. Verification is the final step in the sign-in flow. When a user has verified all required factors, the sign-in attempt will be complete and they will be signed in. - ### Add password support + ## Add password support If your instance is configured to support authenticating with passwords, you must add a few additional steps and verification strategies. You can choose if you want to support providing a password in the `start` step with an additional field, or as an additional verification strategy. For this guide, add it as a standalone verification strategy. @@ -276,7 +276,7 @@ description: Learn how to build a complete sign-in form with Clerk Elements. > [!NOTE] > If your instance isn't configured to use passwords, or any of the strategies outlined here, Clerk Elements will log a warning to the console during development. - ### Customize and add styling + ## Customize and add styling Learn how to style your Clerk Elements components with the [styling guide](/docs/customization/elements/guides/styling). diff --git a/docs/customization/elements/guides/sign-up.mdx b/docs/customization/elements/guides/sign-up.mdx index eb9e04d147..85e41b892d 100644 --- a/docs/customization/elements/guides/sign-up.mdx +++ b/docs/customization/elements/guides/sign-up.mdx @@ -34,7 +34,7 @@ description: Learn how to build a complete sign-up form with Clerk Elements. > - Clerk Elements currently only works with Next.js App Router and [Clerk Core 2](/changelog/2024-04-19){{ target: '_blank' }}. As it gets closer to a stable release, support for additional frameworks will be added. - ### Add a sign-up route + ## Add a sign-up route Create a new route in your Next.js application. The route needs to be an [optional catch-all route](https://nextjs.org/docs/pages/building-your-application/routing/dynamic-routes#optional-catch-all-segments) so the sign-up flow can handled nested paths, as shown in the following example: @@ -54,7 +54,7 @@ description: Learn how to build a complete sign-up form with Clerk Elements. > [!TIP] > If you're getting TypeScript errors on the `@clerk/elements` imports you probably have forgotten to set your [`moduleResolution`](https://www.typescriptlang.org/tsconfig/#moduleResolution) in `tsconfig.json` to `bundler`. - ### Add the start step + ## Add the start step The Clerk authentication flows are made up of **steps**. Steps handle rendering the UI for each part of the flow. To allow users to create a sign-up attempt, the `start` step needs to be rendered. The following example does so with the `` component: @@ -75,7 +75,7 @@ description: Learn how to build a complete sign-up form with Clerk Elements. } ``` - ### Add form fields + ## Add form fields Make it functional by adding input fields. The following example uses the `` component to render the `emailAddress` and `username` fields, as well as the `` component to allow users to sign up with a social connection, like Google: @@ -122,7 +122,7 @@ description: Learn how to build a complete sign-up form with Clerk Elements. `` takes care of wiring up the input with the label element, and `` will render any field-specific errors that get returned from Clerk's API. The `` component provides common actions that are used throughout the flows. In this case, using the `submit` action to render a submit button for the start form. - ### Add verification + ## Add verification As users progress through a sign-up attempt, they may be asked to **verify** a number of authentication factors in the `verifications` step. You can render a form for the user to complete verification, but each [verification strategy](/docs/customization/elements/reference/sign-in#strategy) requires different fields. You must render the form fields conditionally for each authentication strategy your instance supports using the `` component. @@ -195,7 +195,7 @@ description: Learn how to build a complete sign-up form with Clerk Elements. Verification is the final step in the sign-up flow. When a user has verified all required factors, the sign-up attempt will be complete, their account will be created, and they will be signed in. - ### Accept additional fields + ## Accept additional fields Should a user attempt to sign up via Google while a username is a required field, the `continue` step will be necessary to accept the username. The `` component will display any additional required fields. @@ -281,7 +281,7 @@ description: Learn how to build a complete sign-up form with Clerk Elements. > [!NOTE] > Under the hood, Clerk Elements will conditionally render the fields that are necessary to complete the sign up attempt, so there's no need to check the state of the sign up attempt yourself. - ### Customize and add styling + ## Customize and add styling Learn how to style your Clerk Elements components with the [styling guide](/docs/customization/elements/guides/styling). diff --git a/docs/deployments/migrate-from-firebase.mdx b/docs/deployments/migrate-from-firebase.mdx index 9a7971d49b..bb12619e42 100644 --- a/docs/deployments/migrate-from-firebase.mdx +++ b/docs/deployments/migrate-from-firebase.mdx @@ -6,9 +6,9 @@ description: Migrating your user base from Firebase to Clerk is a 2-part process Migrating your user base from Firebase to Clerk is a 2-part process that can be accomplished with just a few steps. - ### Export your Firebase users + ## Export your Firebase users - #### Install the Firebase CLI + ### Install the Firebase CLI If you haven't already, install the Firebase CLI: @@ -16,7 +16,7 @@ Migrating your user base from Firebase to Clerk is a 2-part process that can be npm install -g firebase-tools ``` - #### Log in to Firebase + ### Log in to Firebase Login to your Firebase account via the CLI. @@ -24,7 +24,7 @@ Migrating your user base from Firebase to Clerk is a 2-part process that can be firebase login ``` - #### Find your Firebase project ID + ### Find your Firebase project ID Use the firebase CLI to list your projects and find the project ID you want to export. @@ -32,7 +32,7 @@ Migrating your user base from Firebase to Clerk is a 2-part process that can be firebase projects:list ``` - #### Export your Firebase users using the CLI + ### Export your Firebase users using the CLI Use the firebase CLI to export your users to a JSON file. @@ -52,7 +52,7 @@ Migrating your user base from Firebase to Clerk is a 2-part process that can be You should now have a JSON file called `firebase-users.json` that contains all your Firebase users. - ### Retrieve your password hash parameters + ## Retrieve your password hash parameters In your Firebase project’s dashboard, navigate to **Authentication** and click on the 3 vertical dots at the top of the user's list, then click on **Password hash parameters**. @@ -60,23 +60,23 @@ Migrating your user base from Firebase to Clerk is a 2-part process that can be You can find more information about this page and the values above on [Firebase's documentation](https://firebaseopensource.com/projects/firebase/scrypt/). - ### Create a Node.js script + ## Create a Node.js script Now you have all the information you need to import your Firebase users into Clerk. This example uses Node.js, but you can use any other language or method if you so wish. - #### init npm + ### init npm ```bash {{ filename: 'terminal' }} npm init -y ``` - #### Install dependencies + ### Install dependencies ```bash {{ filename: 'terminal' }} npm i node-fetch@2 ``` - #### Create a script + ### Create a script ```js {{ filename: 'migrate-to-clerk.js' }} const fetch = require('node-fetch') @@ -134,7 +134,7 @@ Migrating your user base from Firebase to Clerk is a 2-part process that can be Here, body will either hold the necessary information to migrate a password-based user or in the case of an OAuth-based user, it'll skip the password check. It will also have the previous user ID as `external_id`, so you can link the newly created users with their existing data. - ### Run the script + ## Run the script ```bash {{ filename: 'terminal' }} node migrate-to-clerk.js diff --git a/docs/guides/authjs-migration.mdx b/docs/guides/authjs-migration.mdx index 0ff9014a9e..7f881daa42 100644 --- a/docs/guides/authjs-migration.mdx +++ b/docs/guides/authjs-migration.mdx @@ -33,12 +33,10 @@ description: Learn how to migrate an application using Auth.js to use Clerk for - Find further support -## Introduction - This guide shows how to migrate an application using Auth.js (formerly NextAuth.js) to use Clerk for authentication. - ### Install `@clerk/nextjs` + ## Install `@clerk/nextjs` Clerk's Next.js SDK gives you access to prebuilt [components](/docs/components/overview), [hooks](/docs/references/nextjs/overview#client-side-helpers), and [helpers](/docs/references/nextjs/overview) for Next.js Server Components, Route Handlers and Middleware. Run the following command to install it: @@ -56,7 +54,7 @@ This guide shows how to migrate an application using Auth.js (formerly NextAuth. ``` - ### Set environment variables + ## Set environment variables Add the following code to your `.env.local` file to set your public and Secret Keys. @@ -67,7 +65,7 @@ This guide shows how to migrate an application using Auth.js (formerly NextAuth. CLERK_SECRET_KEY={{secret}} ``` - ### Wrap your Next.js app in `` + ## Wrap your Next.js app in `` Remove the `` provider from Auth.js and replace it with ``. @@ -104,26 +102,26 @@ This guide shows how to migrate an application using Auth.js (formerly NextAuth. ``` - ### Set up sign-up and sign-in UI + ## Set up sign-up and sign-in UI - #### Account Portal + ### Account Portal Account Portal is the fastest way to authenticate your app. Clerk's Account Portal hosts the ``, ``, ``, and other components for your application. Read more about [Account Portal](/docs/customization/account-portal/getting-started). To use the Account Portal, remove the routes that mount the Auth.js sign-in and sign-up UI. Replace the links to those routes with the [``](/docs/components/unstyled/sign-in-button) or [``](/docs/components/unstyled/sign-out-button) components. - #### Self-hosted UI + ### Self-hosted UI If Clerk's Account Portal pages aren't a good fit your app, you can build a custom sign-in and sign-up UI in one of two ways: - use the [prebuilt components](/docs/references/nextjs/custom-signup-signin-pages), such as the [``](/docs/components/authentication/sign-in) and [``](/docs/components/authentication/sign-up) components - build a [fully custom UI using the Clerk API](/docs/custom-flows/overview), leveraging Clerk's React hooks such as [`useSignIn()`](/docs/references/react/use-sign-in) and [`useSignUp()`](/docs/references/react/use-sign-up) - ### Protect your app + ## Protect your app With Clerk, you can control access to your application in a few different ways. One way is to use Clerk's Middleware to protect your entire application, or specific routes. Another way is to use Clerk's components to conditionally render UI based on the user's authentication state. You can hide or show UI based on whether the user is signed in or not. - #### Control access to your app with Clerk Middleware + ### Control access to your app with Clerk Middleware You will need to remove the Auth.js Middleware from your application, and replace it with the Clerk's Middleware helper, `clerkMiddleware()`. @@ -147,7 +145,7 @@ This guide shows how to migrate an application using Auth.js (formerly NextAuth. } ``` - #### Control access to your app with Clerk's components + ### Control access to your app with Clerk's components To conditionally render UI when the user is signed in, wrap it with [``](/docs/components/control/signed-in). @@ -170,9 +168,9 @@ This guide shows how to migrate an application using Auth.js (formerly NextAuth. } ``` - ### Read user and session data + ## Read user and session data - #### Server-side + ### Server-side Replace any Auth.js `getServerSession(req, res, authOptions)` with Clerk's helpers. @@ -205,7 +203,7 @@ This guide shows how to migrate an application using Auth.js (formerly NextAuth. - #### Client Side + ### Client Side Replace Auth.js's `useSession()` hook with Clerk's hooks. @@ -224,14 +222,14 @@ This guide shows how to migrate an application using Auth.js (formerly NextAuth. } ``` - ### User IDs as Foreign Keys + ## User IDs as Foreign Keys When you migrate to Clerk, you will likely need to resolve the foreign key that you used in your database. If you used the `userId` from NextAuth.js, you could resolve this issue with one of the following two options: - [Use Clerk's `externalId` field](#use-clerks-external-id-field) - [Update your Auth.js database](#update-your-database) - #### Use Clerk's `externalId` field + ### Use Clerk's `externalId` field When you migrate user data from Auth.js to Clerk, Clerk generates new user IDs for each user. If you are using existing user IDs as foreign keys in your database (e.g. in a `user_id` column), you can save those IDs as the user's `externalId` in Clerk. This `externalId` can be included in the session token by adding the following [customization](/docs/backend-requests/making/custom-session-token). The following example will set the user's ID to be `externalId` if one is present, otherwise, it will use the Clerk's user ID. @@ -287,19 +285,19 @@ This guide shows how to migrate an application using Auth.js (formerly NextAuth. > [!NOTE] > You can not access the above from the client-side. If you are using one of Clerk's hooks, then you will need to check if `externalID` exists. If it doesn't, then read the `userId`. - #### Update your database + ### Update your database Alternatively, after the data migration, you can update all the user IDs stored in your database as a foreign key to the new Clerk user IDs. You can read more about user IDs and user data migration in the [Migration Script README](https://github.com/clerk/migration-script?tab=readme-ov-file#handling-the-foreign-key-constraint). - ### Create a Clerk production instance + ## Create a Clerk production instance Every Clerk application has a `Development` and a `Production` instance. Before you start migrating user data, you need to configure your Clerk `Production` instance and migrate your Auth.js users directly into that instance. The [Deploying to Production](/docs/deployments/overview#deploying-to-production) page covers creating a `Production` instance. You can migrate a small set of users on the `Development` instance for testing/staging. To enable importing users to your `Development` instance, add `IMPORT_TO_DEV_INSTANCE=true` to the `.env` for the migration script. - ### Migrate user data from Auth.js to Clerk + ## Migrate user data from Auth.js to Clerk This walkthrough will help you move user data from your existing database to Clerk. @@ -340,7 +338,7 @@ This guide shows how to migrate an application using Auth.js (formerly NextAuth. 1. Check for an error log for any users that were not migrated successfully. - ### Finding further support for migrating from Auth.js to Clerk + ## Finding further support for migrating from Auth.js to Clerk This guide covers the most common steps that you would take for the migration. If you have more complex integrations with Auth.js that are not covered here, don't hesitate to reach out in the [Clerk Discord](/discord){{ target: '_blank' }} by creating a post in the [Support channel](https://discord.gg/bmPVkeqKzZ). diff --git a/docs/guides/basic-rbac.mdx b/docs/guides/basic-rbac.mdx index c162efd9d8..10504d94c5 100644 --- a/docs/guides/basic-rbac.mdx +++ b/docs/guides/basic-rbac.mdx @@ -8,7 +8,7 @@ To control which users can access certain parts of your app, you can use the [ro This guide assumes that you're using Next.js App Router, but the concepts can be adapted to Next.js Pages Router and Remix. - ### Configure the session token + ## Configure the session token Clerk provides [user metadata](/docs/users/metadata#user-metadata), which can be used to store information, and in this case, it can be used to store a user's role. Since `publicMetadata` can only be read but not modified in the browser, it is the safest and most appropriate choice for storing information. @@ -26,7 +26,7 @@ This guide assumes that you're using Next.js App Router, but the concepts can be - ### Create a global TypeScript definition + ## Create a global TypeScript definition 1. In your application's root folder, create a `types/` directory. 1. Inside this directory, create a `globals.d.ts` file with the following code. This file will provide auto-completion and prevent TypeScript errors when working with roles. For this guide, only the `admin` and `moderator` roles will be defined. @@ -46,7 +46,7 @@ This guide assumes that you're using Next.js App Router, but the concepts can be } ``` - ### Set the admin role for your user + ## Set the admin role for your user Later in the guide, you will add a basic admin tool to change a user's role. For now, manually add the `admin` role to your own user account. @@ -61,7 +61,7 @@ This guide assumes that you're using Next.js App Router, but the concepts can be } ``` - ### Create a reusable function to check roles + ## Create a reusable function to check roles Create a helper function to simplify checking roles. @@ -81,7 +81,7 @@ This guide assumes that you're using Next.js App Router, but the concepts can be > [!NOTE] > You can customize the behavior of the `checkRole()` helper function to suit your needs. For example, you could modify it to return the roles a user has or create a `protectByRole()` function that handles role-based redirects. - ### Create the admin dashboard + ## Create the admin dashboard Now, it's time to create an admin dashboard. The first step is to create the `/admin` route. @@ -94,7 +94,7 @@ This guide assumes that you're using Next.js App Router, but the concepts can be } ``` - ### Protect the admin dashboard + ## Protect the admin dashboard To protect the `/admin` route, choose **one** of the two following methods: @@ -104,7 +104,7 @@ This guide assumes that you're using Next.js App Router, but the concepts can be > [!IMPORTANT] > You only need to follow **one** of the following methods to secure your `/admin` route. - #### Option 1: Protect the `/admin` route using middleware + ### Option 1: Protect the `/admin` route using middleware 1. In your app's root directory, create a `middleware.ts` file with the following code. The `createRouteMatcher()` function identifies routes starting with `/admin`. `clerkMiddleware()` intercepts requests to the `/admin` route, and checks the user's role in their `metadata` to verify that they have the `admin` role. If they don't, it redirects them to the home page. @@ -132,7 +132,7 @@ This guide assumes that you're using Next.js App Router, but the concepts can be } ``` - #### Option 2: Protect the `/admin` route at the page-level + ### Option 2: Protect the `/admin` route at the page-level 1. Add the following code to the `app/admin/page.tsx` file. The `checkRole()` function checks if the user has the `admin` role. If they don't, it redirects them to the home page. @@ -151,7 +151,7 @@ This guide assumes that you're using Next.js App Router, but the concepts can be } ``` - ### Create server actions for managing a user's role + ## Create server actions for managing a user's role 1. In your `app/admin/` directory, create an `_actions.ts` file with the following code. The `setRole()` action checks that the current user has the `admin` role before updating the specified user's role using Clerk's [JavaScript Backend SDK](/docs/references/backend/user/update-user). The `removeRole()` action removes the role from the specified user. @@ -193,7 +193,7 @@ This guide assumes that you're using Next.js App Router, but the concepts can be } ``` - ### Create a component for searching for users + ## Create a component for searching for users 1. In your `app/admin/` directory, create a `SearchUsers.tsx` file with the following code. The `` component includes a form for searching for users. When submitted, it appends the search term to the URL as a search parameter. Your `/admin` route will then perform a query based on the updated URL. @@ -226,7 +226,7 @@ This guide assumes that you're using Next.js App Router, but the concepts can be } ``` - ### Refactor the admin dashboard + ## Refactor the admin dashboard With the server action and the search form set up, it's time to refactor the `app/admin/page.tsx`. @@ -298,7 +298,7 @@ This guide assumes that you're using Next.js App Router, but the concepts can be } ``` - ### Finished 🎉 + ## Finished 🎉 The foundation of a custom RBAC (Role-Based Access Control) system is now set up. Roles are attached directly to the user's session, allowing your application to access them without the need for additional network requests. The `checkRole()` helper function simplifies role checks and reduces code complexity. The final component is the admin dashboard, which enables admins to efficiently search for users and manage roles. diff --git a/docs/guides/force-organizations.mdx b/docs/guides/force-organizations.mdx index ecfef6948c..b3ca2eac15 100644 --- a/docs/guides/force-organizations.mdx +++ b/docs/guides/force-organizations.mdx @@ -23,14 +23,12 @@ description: Learn how to hide Personal Accounts and force organizations in your - Limit access to users with active organizations only -## Introduction - In this guide, you will learn how to hide a user's Personal Account in order to appear as if they only have access to organizations. You will also learn how to limit access to your application to only users with active organizations, further enforcing organization-centric access. This is useful for applications that are built for organizations only, such as B2B applications. This guide will be written for Next.js applications using App Router, but the same concepts can be applied to any application using Clerk. - ### Hide Personal Accounts from UI components + ## Hide Personal Accounts from UI components To begin forcing organizations in your application, you need to remove a user's Personal Account from the UI. A user's Personal Account cannot be disabled; it can only be hidden. @@ -68,11 +66,11 @@ This guide will be written for Next.js applications using App Router, but the sa - ### Detect and set an active organization + ## Detect and set an active organization With Clerk, a user can have many organization memberships, but only one of them can be active at a time. - #### Detect an active organization + ### Detect an active organization A session will always include an `orgId` via the [`Auth` object](/docs/references/nextjs/auth-object#auth-object-example-with-active-organization). This can be used to detect if a user has an active organization. @@ -109,7 +107,7 @@ This guide will be written for Next.js applications using App Router, but the sa - #### Set an active organization + ### Set an active organization In the case of [prebuilt components](/docs/components/overview), an organization will _automatically_ be set as active each time the user creates an organization, accepts an invitation, or selects a membership from the organization switcher. In the case of custom flows, you will need to implement the logic for setting an organization as active. The [`useOrganizationList()`](/docs/references/react/use-organization-list) hook provides a `setActive` method to help you with this. @@ -153,7 +151,7 @@ This guide will be written for Next.js applications using App Router, but the sa } ``` - #### Set an active organization based on the URL + ### Set an active organization based on the URL > [!WARNING] > This approach still depends on the `setActive` method, which only runs on the client. Due to this limitation, during SSR, it is possible that `orgId` from `auth()` returns an incorrect value that does not match the organization ID in the URL. @@ -213,7 +211,7 @@ This guide will be written for Next.js applications using App Router, but the sa } ``` - ### Limit access to users with active organizations only + ## Limit access to users with active organizations only Now that you have hidden Personal Accounts from the UI and can detect and set an active organization, you can limit access to your application to users with active organizations only. This will ensure that users without active organizations cannot access your application. @@ -229,7 +227,7 @@ This guide will be written for Next.js applications using App Router, but the sa Based on your use case, you can decide to limit users either in the entire app or a specific part of it. For example, a B2B application might need to limit access to only users with an active organization, whereas a B2B2C application might limit only the `/dashboard` path to users with an active organization. - #### Limit access using the `clerkMiddleware()` helper + ### Limit access using the `clerkMiddleware()` helper Clerk's [`clerkMiddleware()`](/docs/references/nextjs/clerk-middleware) helper can be used in both App Router and Pages Router applications to limit access to users with active organizations only. @@ -324,7 +322,7 @@ This guide will be written for Next.js applications using App Router, but the sa } ``` - #### Limit access using an App Router layout + ### Limit access using an App Router layout In Next.js App Router applications, instead of using `clerkMiddleware()`, you also have the option to use a layout to limit access to users with active organizations only. diff --git a/docs/guides/waitlist.mdx b/docs/guides/waitlist.mdx index cff59729a3..f4012afc5a 100644 --- a/docs/guides/waitlist.mdx +++ b/docs/guides/waitlist.mdx @@ -6,7 +6,7 @@ description: Learn how to add a waitlist to your Next.js application. In [**Waitlist** mode](/docs/authentication/configuration/restrictions#waitlist), users can register their interest in your app by joining a waitlist. This mode is ideal for apps in early development stages or those wanting to generate interest before launch. This guide shows you how to get Clerk integrated and how to add a waitlist to your Next.js application. - ### Install `@clerk/nextjs` + ## Install `@clerk/nextjs` Clerk's [Next.js SDK](/docs/references/nextjs/overview) gives you access to prebuilt components, React hooks, and helpers to make user authentication easier. @@ -26,7 +26,7 @@ In [**Waitlist** mode](/docs/authentication/configuration/restrictions#waitlist) ``` - ### Set your Clerk API keys + ## Set your Clerk API keys @@ -51,7 +51,7 @@ In [**Waitlist** mode](/docs/authentication/configuration/restrictions#waitlist) CLERK_SECRET_KEY={{secret}} ``` - ### Enable Waitlist mode + ## Enable Waitlist mode To enable **Waitlist** mode, follow these steps: @@ -64,7 +64,7 @@ In [**Waitlist** mode](/docs/authentication/configuration/restrictions#waitlist) 1. On the right-side of a user's row, select the menu icon (...). 1. Select **Invite** to invite the user to your application. Select **Deny** to deny the user access to your application. - ### Add the `` component + ## Add the `` component The [``](/docs/components/waitlist) component renders a form that allows users to join for early access to your app. @@ -78,7 +78,7 @@ In [**Waitlist** mode](/docs/authentication/configuration/restrictions#waitlist) } ``` - ### Add `` to your app + ## Add `` to your app @@ -99,14 +99,14 @@ In [**Waitlist** mode](/docs/authentication/configuration/restrictions#waitlist) } ``` - ### Add sign-in functionality + ## Add sign-in functionality To allow users to sign in once they've been approved from the waitlist, you must: - [Add `clerkMiddleware()` to your app.](#add-clerkmiddleware-to-your-app) - [Add a sign-in page.](#add-a-sign-in-page) - #### Add `clerkMiddleware()` to your app + ### Add `clerkMiddleware()` to your app [`clerkMiddleware()`](/docs/references/nextjs/clerk-middleware#clerk-middleware) grants you access to user authentication state throughout your app, on any route or page. It also allows you to protect specific routes from unauthenticated users. To add `clerkMiddleware()` to your app, follow these steps: @@ -134,7 +134,7 @@ In [**Waitlist** mode](/docs/authentication/configuration/restrictions#waitlist) 1. By default, `clerkMiddleware()` will not protect any routes. All routes are public and you must opt-in to protection for routes. See the [`clerkMiddleware()` reference](/docs/references/nextjs/clerk-middleware) to learn how to require authentication for specific routes. - #### Add a sign-in page + ### Add a sign-in page The following example demonstrates how to render the `` component. diff --git a/docs/integrations/databases/convex.mdx b/docs/integrations/databases/convex.mdx index 2c825606aa..bbce2b5bc4 100644 --- a/docs/integrations/databases/convex.mdx +++ b/docs/integrations/databases/convex.mdx @@ -24,14 +24,12 @@ description: Learn how to integrate Clerk into your Convex application. - Access user identity in Convex queries and mutations -## Introduction - Convex is the full-stack TypeScript development platform. With Convex you get to build a backend with a provided realtime database, file storage, text search, scheduling and more. Paired with Clerk's user authentication and management features, you can build a powerful application with minimal effort. This tutorial assumes that you have already [set up a Clerk application](/docs/quickstarts/setup-clerk) and a [React + Convex application](https://docs.convex.dev/quickstart/react){{ target: '_blank' }}. This tutorial will also assume that you have not added Clerk to your application yet. - ### Create a JWT template based on Convex + ## Create a JWT template based on Convex In the Clerk Dashboard, navigate to the [**JWT templates**](https://dashboard.clerk.com/last-active?path=jwt-templates) page. Select the **New template** button to create a new template based on Convex. @@ -47,7 +45,7 @@ This tutorial assumes that you have already [set up a Clerk application](/docs/q By default, Clerk will sign the JWT with a private key automatically generated for your application, which is what most developers use for Convex. If you so choose, you can customize this key. - ### Configure Convex with the Clerk issuer domain + ## Configure Convex with the Clerk issuer domain The next step is to configure Convex with the issuer domain provided by Clerk. From your Clerk **JWT template** screen, find the **Issuer** input and click to **Copy** the URL. @@ -68,11 +66,11 @@ This tutorial assumes that you have already [set up a Clerk application](/docs/q Replace the `domain` string with the **Issuer** URL you copied. - ### Deploy your changes to Convex + ## Deploy your changes to Convex Run `npx convex dev` to automatically sync your configuration to your backend. - ### Install `@clerk/clerk-react` + ## Install `@clerk/clerk-react` Run the following command to install Clerk's React SDK: @@ -90,7 +88,7 @@ This tutorial assumes that you have already [set up a Clerk application](/docs/q ``` - ### Set environment variables + ## Set environment variables In your React project's root folder, you may have an `.env.local` file alongside `package.json` and other configuration files. If you don't see it, create it. @@ -110,7 +108,7 @@ This tutorial assumes that you have already [set up a Clerk application](/docs/q VITE_CLERK_PUBLISHABLE_KEY={{pub_key}} ``` - ### Configure the Clerk and Convex providers + ## Configure the Clerk and Convex providers Both Clerk and Convex have provider components that are required to provide authentication and client context. @@ -149,7 +147,7 @@ This tutorial assumes that you have already [set up a Clerk application](/docs/q ) ``` - ### Access user identity in Convex queries and mutations + ## Access user identity in Convex queries and mutations You can access the user information from the JWT in Convex queries and mutations. Use the `ctx.auth.getUserIdentity()` which returns the parsed information from the JWT, or `null` if the client isn't authenticated. @@ -171,7 +169,7 @@ This tutorial assumes that you have already [set up a Clerk application](/docs/q You can customize the information in the JWT by navigating to the [**JWT templates**](https://dashboard.clerk.com/last-active?path=jwt-templates) page in the Clerk Dashboard. Previously, Convex explicitly listed fields derived from [OpenID standard claims](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims). Now, Convex allows keys to accept [custom claims](https://docs.convex.dev/api/interfaces/server.UserIdentity). - ### Finished! + ## Finished! You now have a fully functioning React and Convex application with Clerk authentication. Be aware that Convex may require usage of their custom hooks and methods rather than Clerk's, such as using Convex's `useConvexAuth()` hook instead of Clerk's `useAuth()` hook in some cases. For more information on how to use Convex with Clerk, see the [Convex docs](https://docs.convex.dev/auth/clerk). diff --git a/docs/integrations/databases/fauna.mdx b/docs/integrations/databases/fauna.mdx index 40ed46991e..0e01ef4f9f 100644 --- a/docs/integrations/databases/fauna.mdx +++ b/docs/integrations/databases/fauna.mdx @@ -30,7 +30,7 @@ Integrating Fauna with Clerk gives you the benefits of using a Fauna database wh This guide will walk you through the steps to integrate Fauna with Clerk in your Next.js app. - ### Get your Clerk Frontend API URL and JWKS URL + ## Get your Clerk Frontend API URL and JWKS URL Add the following keys to your `.env.local` file. These keys can always be retrieved from the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page in the Clerk Dashboard. @@ -52,7 +52,7 @@ This guide will walk you through the steps to integrate Fauna with Clerk in your NEXT_PUBLIC_CLERK_JWKS_URL={{jwks_url}} ``` - ### Configure Fauna + ## Configure Fauna 1. Navigate to the [Fauna Dashboard](https://dashboard.fauna.com/) and select your database. 1. Select the **Access Providers** tab and select **Create Access Provider**. @@ -76,7 +76,7 @@ This guide will walk you through the steps to integrate Fauna with Clerk in your ``` 1. Select **Save**. - ### Create a JWT template in Clerk + ## Create a JWT template in Clerk Clerk's JWT templates allow you to generate a new valid Fauna authentication token (JWT) for each signed in user. These tokens allow authenticated users to access your data with Fauna's API. @@ -90,7 +90,7 @@ This guide will walk you through the steps to integrate Fauna with Clerk in your - In the **Claims** section, set the `aud` claim to the **Audience URL** you copied from Fauna in Step 2. The URL format should be `https://db.fauna.com/db/`. You can include additional claims if you’d like, but `aud` is the only required one. [Shortcodes](/docs/backend-requests/making/jwt-templates#shortcodes) are available to make adding dynamic user values easy. - Select **Save** from the notification bubble to complete setup. - ### Install the Fauna library + ## Install the Fauna library Add the Fauna library to your project. @@ -108,7 +108,7 @@ This guide will walk you through the steps to integrate Fauna with Clerk in your ``` - ### Authenticate Fauna queries in your Next.js app + ## Authenticate Fauna queries in your Next.js app You can now create Fauna JWTs in Clerk using the JWT template you created in the previous step. Generate the Fauna JWT by calling Clerk's [`useAuth().getToken`](/docs/references/react/use-auth) method, and use it to authenticate with Fauna as an end user, as shown in the following example: diff --git a/docs/integrations/databases/firebase.mdx b/docs/integrations/databases/firebase.mdx index 51c692f0eb..61219e5315 100644 --- a/docs/integrations/databases/firebase.mdx +++ b/docs/integrations/databases/firebase.mdx @@ -32,7 +32,7 @@ Integrating Firebase with Clerk gives you the benefits of using Firebase's featu > See the [demo repo](https://github.com/clerk/clerk-firebase-nextjs) for a full example of how to integrate Firebase with Clerk in a Next.js app. - ### Configure the integration + ## Configure the integration The Firebase integration enables you to use Clerk to generate a valid authentication token to send to Firebase Auth. This enables you to leverage Clerk's prebuilt components, auth provider options, and more, while accessing Firebase products like Firestore with a session validated by Firebase Auth. @@ -68,7 +68,7 @@ Integrating Firebase with Clerk gives you the benefits of using Firebase's featu - ### Enable authentication in Firebase + ## Enable authentication in Firebase To use Firebase auth, ensure authentication is enabled in your Firebase dashboard. To do so: @@ -77,7 +77,7 @@ Integrating Firebase with Clerk gives you the benefits of using Firebase's featu 1. Select **Get started**. 1. Enable any sign-in method you want, such as **Email/Password**. - ### Add a Security Rule to your Firestore database (optional) + ## Add a Security Rule to your Firestore database (optional) Adding the [Cloud Firestore](https://firebase.google.com/docs/firestore/quickstart) feature in your Firebase application is optional. @@ -93,7 +93,7 @@ Integrating Firebase with Clerk gives you the benefits of using Firebase's featu } ``` - ### Get your Firebase config object + ## Get your Firebase config object To connect to your Firebase app in your code, you need a config object from your Firebase project. To find it: @@ -115,7 +115,7 @@ Integrating Firebase with Clerk gives you the benefits of using Firebase's featu See [Google's Firebase documentation](https://support.google.com/firebase/answer/7015592) for more information on the config object. - ### Use Firebase with Clerk in your code + ## Use Firebase with Clerk in your code Now that you have configured the integration, and you have retrieved your Firebase config object, it's time to use Firebase with Clerk in your code. diff --git a/docs/integrations/databases/instantdb.mdx b/docs/integrations/databases/instantdb.mdx index 43522defff..b72937377c 100644 --- a/docs/integrations/databases/instantdb.mdx +++ b/docs/integrations/databases/instantdb.mdx @@ -35,7 +35,7 @@ Integrating [InstantDB](https://www.instantdb.com/) with Clerk gives you the ben This guide will walk you through the steps to integrate InstantDB with Clerk in your Next.js app. - ### Configure your Clerk session token + ## Configure your Clerk session token InstantDB uses Clerk's [session token](/docs/backend-requests/resources/session-tokens) to authenticate users. To use InstantDB with Clerk, you need to include the `email` claim in your session token. @@ -50,12 +50,12 @@ This guide will walk you through the steps to integrate InstantDB with Clerk in You can have additional claims as long as the `email` claim is set to `{{user.primary_email_address}}`. - ### Get your Clerk Publishable Key + ## Get your Clerk Publishable Key 1. In the Clerk Dashboard, navigate to the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page. 1. In the **Quick Copy** section, copy your Clerk Publishable Key. - ### Configure InstantDB + ## Configure InstantDB 1. In the InstantDB dashboard, navigate to the [**Auth**](https://www.instantdb.com/dash?t=auth) tab. 1. Select **Setup Clerk**. @@ -63,7 +63,7 @@ This guide will walk you through the steps to integrate InstantDB with Clerk in 1. Confirm the **The session token has the "email" claim.** message. 1. Select **Add Clerk app**. - ### Install the InstantDB library + ## Install the InstantDB library Run the following command to add the InstantDB library to your project. @@ -81,7 +81,7 @@ This guide will walk you through the steps to integrate InstantDB with Clerk in ``` - ### Integrate InstantDB to your Clerk application + ## Integrate InstantDB to your Clerk application To sign in to InstantDB with Clerk, you need to: diff --git a/docs/integrations/databases/neon.mdx b/docs/integrations/databases/neon.mdx index 56abd969e8..d62eba71b1 100644 --- a/docs/integrations/databases/neon.mdx +++ b/docs/integrations/databases/neon.mdx @@ -23,7 +23,7 @@ description: Learn how to integrate Clerk into your Neon application. This tutorial demonstrates how to integrate Neon Postgres with Clerk in a Next.js application, using `drizzle-orm` and `drizzle-kit` to interact with the database. The tutorial guides you through setting up a simple application that enables users to add, view, and delete messages using Server Actions and Middleware with Clerk. - ### Create a new Next.js project + ## Create a new Next.js project 1. Create a new Next.js project using the following command: ```sh {{ filename: 'terminal' }} @@ -37,11 +37,11 @@ This tutorial demonstrates how to integrate Neon Postgres with Clerk in a Next.j npm install -D drizzle-kit ``` - ### Integrate the Next.js Clerk SDK + ## Integrate the Next.js Clerk SDK Follow the [Next.js quickstart](/docs/quickstarts/nextjs) to integrate the Clerk Next.js SDK into your application. - ### Protect your application routes + ## Protect your application routes To ensure that only authenticated users can access your application, modify [`clerkMiddleware`](/docs/references/nextjs/clerk-middleware) to require authentication for every route. @@ -62,7 +62,7 @@ This tutorial demonstrates how to integrate Neon Postgres with Clerk in a Next.j } ``` - ### Set your neon connection string + ## Set your neon connection string Add the Neon connection string to your project's environment variables. You can find the Neon connection string in the [Neon console](https://console.neon.tech/) - see the [Neon docs](https://neon.tech/docs/connect/connect-from-any-app) for more information. @@ -74,7 +74,7 @@ This tutorial demonstrates how to integrate Neon Postgres with Clerk in a Next.j CLERK_SECRET_KEY={{secret}} ``` - ### Set up the application schema and database connection + ## Set up the application schema and database connection 1. Inside the `app/`, create a `db/` directory. @@ -110,7 +110,7 @@ This tutorial demonstrates how to integrate Neon Postgres with Clerk in a Next.j }) ``` - ### Push the schema to the database + ## Push the schema to the database 1. To load the schema into the database, create a `drizzle.config.ts` file at the root of your project and add the following configuration: @@ -139,7 +139,7 @@ This tutorial demonstrates how to integrate Neon Postgres with Clerk in a Next.j npx drizzle-kit push ``` - ### Create Server Actions to handle user interactions + ## Create Server Actions to handle user interactions To handle form submissions for adding and deleting user messages, create two Server Actions in `app/actions.ts`. Use Clerk's [`auth()` helper](/docs/references/nextjs/auth) to obtain the user ID, which will be used to interact with the database. @@ -170,7 +170,7 @@ This tutorial demonstrates how to integrate Neon Postgres with Clerk in a Next.j } ``` - ### Create the UI for the Home Page + ## Create the UI for the Home Page In your `app/page.tsx` file, add the following code to create the UI for the home page. If a message exists, the user can view and delete it; otherwise, they can add a new message. @@ -211,7 +211,7 @@ This tutorial demonstrates how to integrate Neon Postgres with Clerk in a Next.j } ``` - ### Run the application + ## Run the application Run your application and open `http://localhost:3000` in your browser. Sign in with Clerk and interact with the application to add and delete user messages. diff --git a/docs/quickstarts/astro.mdx b/docs/quickstarts/astro.mdx index f1767b7ed2..c46a85d9c8 100644 --- a/docs/quickstarts/astro.mdx +++ b/docs/quickstarts/astro.mdx @@ -31,7 +31,7 @@ description: Add authentication and user management to your Astro app with Clerk - ### Install `@clerk/astro` + ## Install `@clerk/astro` Clerk's [Astro SDK](/docs/references/astro/overview) provides a set of components, hooks, and stores that make it easy to build authentication and user management features in your Astro app. @@ -51,7 +51,7 @@ description: Add authentication and user management to your Astro app with Clerk ``` - ### Set your Clerk API keys + ## Set your Clerk API keys Add the following keys to your `.env.local` file. These keys can always be retrieved from the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page in the Clerk Dashboard. @@ -70,7 +70,7 @@ description: Add authentication and user management to your Astro app with Clerk CLERK_SECRET_KEY={{secret}} ``` - ### Update `astro.config.mjs` + ## Update `astro.config.mjs` To configure Clerk in your Astro app, you will need to update your `astro.config.mjs`. @@ -90,7 +90,7 @@ description: Add authentication and user management to your Astro app with Clerk }) ``` - ### Add `clerkMiddleware()` to your app + ## Add `clerkMiddleware()` to your app [`clerkMiddleware()`](/docs/references/astro/clerk-middleware) grants you access to user authentication state throughout your app, on any route or page. It also allows you to protect specific routes from unauthenticated users. To add `clerkMiddleware()` to your app, follow these steps: @@ -105,7 +105,7 @@ description: Add authentication and user management to your Astro app with Clerk ``` 1. By default, `clerkMiddleware()` will not protect any routes. All routes are public and you must opt-in to protection for routes. See the [`clerkMiddleware()` reference](/docs/references/astro/clerk-middleware) to learn how to require authentication for specific routes. - ### Add TypeScript declarations + ## Add TypeScript declarations Update the `env.d.ts` file in your `src/` directory to add type definitions for the `locals` added by the middleware. @@ -118,7 +118,7 @@ description: Add authentication and user management to your Astro app with Clerk /// ``` - ### Add Clerk components to your app + ## Add Clerk components to your app You can control which content signed-in and signed-out users can see with Clerk's [prebuilt control components](/docs/components/overview#what-are-control-components). Create a header using the following components: @@ -170,7 +170,7 @@ description: Add authentication and user management to your Astro app with Clerk ``` - ### Create your first user + ## Create your first user Run your project with the following command: diff --git a/docs/quickstarts/chrome-extension.mdx b/docs/quickstarts/chrome-extension.mdx index f361d050e4..fef197f686 100644 --- a/docs/quickstarts/chrome-extension.mdx +++ b/docs/quickstarts/chrome-extension.mdx @@ -27,13 +27,13 @@ description: Add authentication and user management to your Chrome Extension wit - ### Configure your authentication options + ## Configure your authentication options When creating your Clerk application in the Clerk Dashboard, your authentication options will depend on how you configure your Chrome Extension. Chrome Extensions can be used as a popup, a side panel, or in conjunction with a web app. Popups and side panels have limited authentication options. [Learn more about what options are available.](/docs/references/chrome-extension/overview#authenication-options) This guide will use a popup. - ### Create a new app using the Plasmo framework + ## Create a new app using the Plasmo framework [Plasmo](https://docs.plasmo.com/framework) is a browser extension framework that includes hot reloading and creating development and production extension builds easily from the same code. @@ -46,7 +46,7 @@ description: Add authentication and user management to your Chrome Extension wit cd clerk-chrome-extension ``` - ### Install `@clerk/chrome-extension` + ## Install `@clerk/chrome-extension` Clerk's [Chrome Extension SDK](/docs/references/chrome-extension/overview) gives you access to prebuilt components, React hooks, and helpers to make user authentication easier. @@ -56,7 +56,7 @@ description: Add authentication and user management to your Chrome Extension wit pnpm add @clerk/chrome-extension ``` - ### Set your Clerk API keys + ## Set your Clerk API keys Plasmo offers [several options](https://docs.plasmo.com/framework/env) for environment variable files, as the same codebase can be used for development and production builds, as well as for targeting different browsers. This guide uses `.env.development` and `.env.chrome` files. @@ -77,7 +77,7 @@ description: Add authentication and user management to your Chrome Extension wit CLERK_FRONTEND_API={{fapi_url}} ``` - ### Add `` to your app + ## Add `` to your app @@ -107,7 +107,7 @@ description: Add authentication and user management to your Chrome Extension wit export default IndexPopup ``` - ### Create a header with Clerk components + ## Create a header with Clerk components You can control what content signed in and signed out users can see with Clerk's [prebuilt components](/docs/components/overview). Create a header with the following Clerk components. (With Chrome Extensions, you can also add this logic to a footer). @@ -157,7 +157,7 @@ description: Add authentication and user management to your Chrome Extension wit export default IndexPopup ``` - ### Update `` props for Chrome Extension navigation + ## Update `` props for Chrome Extension navigation To avoid navigation errors, set the `afterSignOutUrl`, `signInFallbackRedirectUrl` and `signUpFallbackRedirectUrl` props for ``. Chrome Extensions don't use an `http` URL, such as `http://localhost:3000`. Instead, they use a `chrome-extension://` URL appended with an unique extension ID called a CRX ID. This URL is what you will pass to these props. @@ -209,7 +209,7 @@ description: Add authentication and user management to your Chrome Extension wit export default IndexPopup ``` - ### Create a consistent CRX ID for your extension + ## Create a consistent CRX ID for your extension Chrome Extensions have a unique CRX ID that rotates by default, which can cause errors with the Clerk integration. To avoid these problems, ensure that you have a **consistent** CRX ID in both development and production for your extension by following these steps: @@ -217,7 +217,7 @@ description: Add authentication and user management to your Chrome Extension wit 1. Select **Generate KeyPairs**. 1. Save the **Private Key** somewhere secure in case you need it in the future. Save the **Public Key** and the **CRX ID** for the next steps. - ### Create an `.env.chrome` file to store your public key + ## Create an `.env.chrome` file to store your public key Create an `.env.chrome` file and add your public key to it, as shown in the following example: @@ -225,7 +225,7 @@ description: Add authentication and user management to your Chrome Extension wit CRX_PUBLIC_KEY= ``` - ### Edit your `package.json` to use the new public key + ## Edit your `package.json` to use the new public key Plasmo [uses the `package.json` to generate a `manifest.json` on build](https://docs.plasmo.com/framework#where-is-the-manifestjson-file), and allows for the use of environment variables in `package.json`. @@ -246,7 +246,7 @@ description: Add authentication and user management to your Chrome Extension wit } ``` - ### Use `pnpm dev` to start your development server and create a build + ## Use `pnpm dev` to start your development server and create a build Plasmo facilitates Chrome Extension development by automatically "hot loading" the app whenever you save a changed file in the project. This ensures the `build/chrome-mv3-dev` folder remains up to date. Without the plugin, you would need to manually execute the build command and reload your Chrome Extension after each change. Plasmo automates this process, streamlining development. @@ -256,7 +256,7 @@ description: Add authentication and user management to your Chrome Extension wit pnpm dev ``` - ### Load your Chrome Extension into your Chromium-based browser + ## Load your Chrome Extension into your Chromium-based browser To load your Chrome Extension, follow these steps: @@ -266,7 +266,7 @@ description: Add authentication and user management to your Chrome Extension wit 1. Navigate to where your project is located and select the `build/chrome-mv3-dev` folder. Then select **Select**. Your extension will now be loaded and shown in the list of extensions. 1. Confirm that the ID shown in your extension matches the CRX ID you saved [earlier](#create-a-consistent-crx-id-for-your-extension). - ### Test your Chrome Extension + ## Test your Chrome Extension In your Chrome browser, open the extension popup. Ensure that the `` appears, and that selecting it opens the `` modal. Sign in and ensure that the `` appears in the header. diff --git a/docs/quickstarts/expo.mdx b/docs/quickstarts/expo.mdx index c9d126d8cf..1ef8b7da8e 100644 --- a/docs/quickstarts/expo.mdx +++ b/docs/quickstarts/expo.mdx @@ -33,7 +33,7 @@ description: Add authentication and user management to your Expo app with Clerk. - ### Install `@clerk/clerk-expo` + ## Install `@clerk/clerk-expo` Clerk's [Expo SDK](/docs/references/expo/overview) gives you access to prebuilt components, hooks, and helpers to make user authentication easier. @@ -53,7 +53,7 @@ description: Add authentication and user management to your Expo app with Clerk. ``` - ### Install `@clerk/types` (optional) + ## Install `@clerk/types` (optional) Clerk's `@clerk/types` package provides TypeScript type definitions. @@ -73,7 +73,7 @@ description: Add authentication and user management to your Expo app with Clerk. ``` - ### Set your Clerk API keys + ## Set your Clerk API keys Add your Clerk Publishable Key to your `.env` file. It can always be retrieved from the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page in the Clerk Dashboard. @@ -91,7 +91,7 @@ description: Add authentication and user management to your Expo app with Clerk. EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY={{pub_key}} ``` - ### Add `` to your root layout + ## Add `` to your root layout @@ -122,7 +122,7 @@ description: Add authentication and user management to your Expo app with Clerk. } ``` - ### Configure the token cache + ## Configure the token cache Clerk stores the active user's session token in memory by default. In Expo apps, the recommended way to store sensitive data, such as tokens, is by using `expo-secure-store` which encrypts the data before storing it. @@ -201,11 +201,11 @@ description: Add authentication and user management to your Expo app with Clerk. > [!TIP] > When you sign a user out with [`signOut()`](/docs/references/react/use-auth#use-auth-returns), Clerk will remove the user's session JWT from the token cache. - ### Add sign-up and sign-in pages + ## Add sign-up and sign-in pages Clerk currently only supports [control components](/docs/components/overview#what-are-control-components) for Expo native. UI components are only available for Expo web. Instead, you must build [custom flows](/docs/custom-flows/overview) using Clerk's API. The following sections demonstrate how to build [custom email/password sign-up and sign-in flows](/docs/custom-flows/email-password). If you want to use different authentication methods, such as passwordless or OAuth, see the dedicated custom flow guides. - #### Layout page + ### Layout page First, protect your sign-up and sign-in pages. @@ -228,7 +228,7 @@ description: Add authentication and user management to your Expo app with Clerk. } ``` - #### Sign-up page + ### Sign-up page 1. In the `(auth)` group, create a `sign-up.tsx` file. 1. Paste the following code. The [`useSignUp()`](/docs/references/react/use-sign-up) hook is used to create a sign-up flow. The user can sign up using their email and password and will receive an email verification code to confirm their email. @@ -336,7 +336,7 @@ description: Add authentication and user management to your Expo app with Clerk. } ``` - #### Sign-in page + ### Sign-in page 1. In the `(auth)` group, create a `sign-in.tsx` file. 1. Paste the following code. The [`useSignIn()`](/docs/references/react/use-sign-in) hook is used to create a sign-in flow. The user can sign in using email address and password, or navigate to the sign-up page. @@ -410,7 +410,7 @@ description: Add authentication and user management to your Expo app with Clerk. For more information about building these custom flows, including guided comments in the code examples, see the [Build a custom email/password authentication flow](/docs/custom-flows/email-password) guide. - ### Conditionally render content + ## Conditionally render content You can control which content signed-in and signed-out users can see with Clerk's [prebuilt control components](/docs/components/overview#what-are-control-components). For this quickstart, you'll use: @@ -459,7 +459,7 @@ description: Add authentication and user management to your Expo app with Clerk. } ``` - ### Create your first user + ## Create your first user Run your project with the following command: diff --git a/docs/quickstarts/express.mdx b/docs/quickstarts/express.mdx index dd3f092403..4ce49c5754 100644 --- a/docs/quickstarts/express.mdx +++ b/docs/quickstarts/express.mdx @@ -33,7 +33,7 @@ description: Learn how to use Clerk to quickly and easily add secure authenticat Learn how to integrate Clerk into your Express backend for secure user authentication and management. This guide covers backend implementation only and requires a Clerk frontend SDK in order for any of this to work. - ### Install `@clerk/express` + ## Install `@clerk/express` Clerk's [Express SDK](/docs/references/express/overview) ships with a variety of helpers for the backend to make user authentication easier. @@ -53,7 +53,7 @@ Learn how to integrate Clerk into your Express backend for secure user authentic ``` - ### Set your Clerk API keys + ## Set your Clerk API keys Add the following keys to your `.env` file. These keys can always be retrieved from the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page in the Clerk Dashboard. @@ -88,7 +88,7 @@ Learn how to integrate Clerk into your Express backend for secure user authentic ``` - ### Add `clerkMiddleware()` to your application + ## Add `clerkMiddleware()` to your application The [`clerkMiddleware()`](/docs/references/express/overview#clerk-middleware) function checks the request's cookies and headers for a session JWT and, if found, attaches the [`Auth`](/docs/references/nextjs/auth-object#auth-object){{ target: '_blank' }} object to the `request` object under the `auth` key. @@ -106,7 +106,7 @@ Learn how to integrate Clerk into your Express backend for secure user authentic }) ``` - ### Protect your routes using `requireAuth()` + ## Protect your routes using `requireAuth()` To protect your routes, use the [`requireAuth()`](/docs/references/express/overview#require-auth) middleware. This middleware functions similarly to `clerkMiddleware()`, but also protects your routes by redirecting unauthenticated users to the sign-in page. diff --git a/docs/quickstarts/fastify.mdx b/docs/quickstarts/fastify.mdx index 1d760b5f72..9e146a2029 100644 --- a/docs/quickstarts/fastify.mdx +++ b/docs/quickstarts/fastify.mdx @@ -39,7 +39,7 @@ Learn how to integrate Clerk into your Fastify backend for secure user authentic > This guide uses ECMAScript Modules (ESM). To use ESM in your project, you must include `"type": "module"` in your `package.json`. - ### Install `@clerk/fastify` + ## Install `@clerk/fastify` [Clerk's Fastify SDK](https://github.com/clerk/javascript/tree/main/packages/fastify) provides a range of backend utilities to simplify user authentication and management in your application. @@ -59,7 +59,7 @@ Learn how to integrate Clerk into your Fastify backend for secure user authentic ``` - ### Set your Clerk API keys + ## Set your Clerk API keys Add the following keys to your `.env.local` file. These keys can always be retrieved from the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page in the Clerk Dashboard. @@ -78,7 +78,7 @@ Learn how to integrate Clerk into your Fastify backend for secure user authentic CLERK_SECRET_KEY={{secret}} ``` - ### Configure `clerkPlugin` for all routes + ## Configure `clerkPlugin` for all routes The `clerkPlugin` is a Fastify plugin provided by Clerk to integrate authentication into your Fastify application. To ensure that Clerk's authentication and user management features are applied across your Fastify application, configure the `clerkPlugin` to handle all routes or limit it to specific ones. @@ -108,7 +108,7 @@ Learn how to integrate Clerk into your Fastify backend for secure user authentic start() ``` - ### Use `getAuth()` to access the auth state and protect routes + ## Use `getAuth()` to access the auth state and protect routes The following example uses [`getAuth()`](/docs/references/nextjs/get-auth){{ target: '_blank' }} to retrieve the `userId`, which is used to protect the route and is passed to [`clerkClient.users.getUser()`](/docs/references/backend/user/get-user){{ target: '_blank' }} to retrieve the current user's `User` object. @@ -150,7 +150,7 @@ Learn how to integrate Clerk into your Fastify backend for secure user authentic ``` -### Configure `clerkPlugin` for specific routes +## Configure `clerkPlugin` for specific routes If you want to use Clerk for specific pages only, you can register the plugin for specific routes. In the following example, the routes are split into protected and public routes. diff --git a/docs/quickstarts/ios.mdx b/docs/quickstarts/ios.mdx index 0cb4ffdf5a..fd19fc1cd5 100644 --- a/docs/quickstarts/ios.mdx +++ b/docs/quickstarts/ios.mdx @@ -23,17 +23,17 @@ description: Add authentication and user management to your iOS app with Clerk. - ### Create an iOS Project + ## Create an iOS Project To get started using Clerk with iOS, create a new project in Xcode. Select SwiftUI as your interface and Swift as your language. See the [Xcode documentation](https://developer.apple.com/documentation/xcode/creating-an-xcode-project-for-an-app) for more information. - ### Install the Clerk iOS SDK + ## Install the Clerk iOS SDK Follow [the Swift Package Manager instructions](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app) to install Clerk as a dependency. When prompted for the package URL, enter [https://github.com/clerk/clerk-ios](https://github.com/clerk/clerk-ios). Be sure to add the package to your target. - ### Load Clerk + ## Load Clerk To use Clerk in your app, you must first configure and load `Clerk`. @@ -69,7 +69,7 @@ description: Add authentication and user management to your iOS app with Clerk. } ``` - ### Conditionally render content + ## Conditionally render content To render content based on whether a user is authenticated or not: @@ -97,9 +97,9 @@ description: Add authentication and user management to your iOS app with Clerk. } ``` - ### Create views for sign-up and sign-in + ## Create views for sign-up and sign-in - #### `SignUpView` + ### `SignUpView` The following example creates a `SignUpView` that allows users to sign up using their email address and password, and sends an email verification code to confirm their email address. @@ -165,7 +165,7 @@ description: Add authentication and user management to your iOS app with Clerk. } ``` - #### `SignInView` + ### `SignInView` The following example creates a `SignInView` that allows users to sign in using their email address and password. @@ -205,7 +205,7 @@ description: Add authentication and user management to your iOS app with Clerk. } ``` - #### `SignUpOrSignInView` + ### `SignUpOrSignInView` Finally, create a `SignUpOrSignInView` container view that allows users to switch between sign up and sign in. @@ -238,7 +238,7 @@ description: Add authentication and user management to your iOS app with Clerk. } ``` - ### Allow users to sign up or sign in + ## Allow users to sign up or sign in Go back to your `ContentView` and render your newly created `SignUpOrSignInView` when the user isn't signed in. @@ -261,7 +261,7 @@ description: Add authentication and user management to your iOS app with Clerk. } ``` - ### Allow users to sign out + ## Allow users to sign out Finally, provide users with a way to sign out of your app: diff --git a/docs/quickstarts/javascript.mdx b/docs/quickstarts/javascript.mdx index 9feb90d979..4d917d89bc 100644 --- a/docs/quickstarts/javascript.mdx +++ b/docs/quickstarts/javascript.mdx @@ -36,7 +36,7 @@ Use the following tabs to choose your preferred method. - ### Set up a JavaScript app using Vite + ## Set up a JavaScript app using Vite To install Clerk's JavaScript SDK, you need to use a bundler like [Vite](https://vitejs.dev/) or [Webpack](https://webpack.js.org/). @@ -65,7 +65,7 @@ Use the following tabs to choose your preferred method. ``` - ### Install `@clerk/clerk-js` + ## Install `@clerk/clerk-js` Run the following command to add the JavaScript SDK to your project: @@ -83,7 +83,7 @@ Use the following tabs to choose your preferred method. ``` - ### Set your Clerk API keys + ## Set your Clerk API keys It's recommended to use environment variables to store your Clerk Publishable Key. In JavaScript projects, you can add these values in an `.env` file and load them into your app using a package like [`dotenv`](https://www.npmjs.com/package/dotenv). For Vite projects, environment variables in an `.env` file at the project root are automatically accessible through the [`import.meta.env` object](https://vitejs.dev/guide/env-and-mode.html#env-variables). @@ -109,7 +109,7 @@ Use the following tabs to choose your preferred method. const clerkPubKey = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY ``` - ### Initialize Clerk + ## Initialize Clerk To initialize Clerk, import the `Clerk` class and instantiate it with your Clerk Publishable Key. Then, call the `load()` method, as shown in the following example: @@ -127,7 +127,7 @@ Use the following tabs to choose your preferred method. > [!NOTE] > Calling the `load()` method initializes Clerk. For more information on the `load()` method and what options you can pass to it, see the [reference documentation](/docs/references/javascript/clerk/clerk#load). - ### Add Clerk components to your app + ## Add Clerk components to your app Clerk's [prebuilt components](/docs/components/overview) are the easiest way to add authentication and user management to your app. They come styled out-of-the-box and are customizable to fit your app's design. @@ -183,7 +183,7 @@ Use the following tabs to choose your preferred method. ``` - ### Create your first user + ## Create your first user Run your project with the following command: @@ -209,7 +209,7 @@ Use the following tabs to choose your preferred method. - ### Add the SDK using a ` ``` - ### Listen for the `load` event + ## Listen for the `load` event Below the ` tag that initializes the SDK, create another ` ``` - ### Allow users to sign in or out + ## Allow users to sign in or out Clerk's [prebuilt components](/docs/components/overview) are the easiest way to add authentication and user management to your app. They come styled out-of-the-box and are customizable to fit your app's design. @@ -295,7 +295,7 @@ Use the following tabs to choose your preferred method. -### More resources +## More resources - [Clerk class reference](/docs/references/javascript/clerk/clerk) diff --git a/docs/quickstarts/nextjs.mdx b/docs/quickstarts/nextjs.mdx index 7c6a8bcda1..1c6e51bce7 100644 --- a/docs/quickstarts/nextjs.mdx +++ b/docs/quickstarts/nextjs.mdx @@ -25,7 +25,7 @@ description: Add authentication and user management to your Next.js app with Cle - ### Install `@clerk/nextjs` + ## Install `@clerk/nextjs` Clerk's [Next.js SDK](/docs/references/nextjs/overview) gives you access to prebuilt components, React hooks, and helpers to make user authentication easier. @@ -45,7 +45,7 @@ description: Add authentication and user management to your Next.js app with Cle ``` - ### Set your Clerk API keys + ## Set your Clerk API keys @@ -70,7 +70,7 @@ description: Add authentication and user management to your Next.js app with Cle CLERK_SECRET_KEY={{secret}} ``` - ### Add `clerkMiddleware()` to your app + ## Add `clerkMiddleware()` to your app [`clerkMiddleware()`](/docs/references/nextjs/clerk-middleware#clerk-middleware) grants you access to user authentication state throughout your app, on any route or page. It also allows you to protect specific routes from unauthenticated users. To add `clerkMiddleware()` to your app, follow these steps: @@ -95,7 +95,7 @@ description: Add authentication and user management to your Next.js app with Cle ``` 1. By default, `clerkMiddleware()` will not protect any routes. All routes are public and you must opt-in to protection for routes. See the [`clerkMiddleware()` reference](/docs/references/nextjs/clerk-middleware) to learn how to require authentication for specific routes. - ### Add `` and Clerk components to your app + ## Add `` and Clerk components to your app @@ -157,7 +157,7 @@ description: Add authentication and user management to your Next.js app with Cle ``` - ### Create your first user + ## Create your first user Run your project with the following command: diff --git a/docs/quickstarts/react-router.mdx b/docs/quickstarts/react-router.mdx index cdaab7e726..4f171e5652 100644 --- a/docs/quickstarts/react-router.mdx +++ b/docs/quickstarts/react-router.mdx @@ -34,7 +34,7 @@ description: Learn how to use Clerk to quickly and easily add secure authenticat Clerk's [React Router SDK](/docs/references/react-router/overview) provides prebuilt components, hooks, and stores to make it easy to integrate authentication and user management in your React Router app. This guide assumes that you're using [React Router v7 or later](https://api.reactrouter.com/v7). - ### Install `@clerk/react-router` + ## Install `@clerk/react-router` Run the following command to install the SDK: @@ -52,7 +52,7 @@ Clerk's [React Router SDK](/docs/references/react-router/overview) provides preb ``` - ### Set your Clerk API keys + ## Set your Clerk API keys Add the following keys to your `.env` file. These keys can always be retrieved from the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page in the Clerk Dashboard. @@ -71,7 +71,7 @@ Clerk's [React Router SDK](/docs/references/react-router/overview) provides preb CLERK_SECRET_KEY={{secret}} ``` - ### Configure `rootAuthLoader()` + ## Configure `rootAuthLoader()` The `rootAuthLoader()` function provides access to authentication state in any React Router route. @@ -153,7 +153,7 @@ Clerk's [React Router SDK](/docs/references/react-router/overview) provides preb } ``` - ### Add `` and Clerk components to your app + ## Add `` and Clerk components to your app @@ -198,7 +198,7 @@ Clerk's [React Router SDK](/docs/references/react-router/overview) provides preb // Rest of the root.tsx code ``` - ### Create your first user + ## Create your first user Run your project with the following command: diff --git a/docs/quickstarts/react.mdx b/docs/quickstarts/react.mdx index a7384e1c8d..c904071c13 100644 --- a/docs/quickstarts/react.mdx +++ b/docs/quickstarts/react.mdx @@ -28,7 +28,7 @@ description: Add authentication and user management to your React app with Clerk - ### Create a React app using Vite + ## Create a React app using Vite Run the following commands to create a new React app using [Vite](https://vitejs.dev/guide/#scaffolding-your-first-vite-project): @@ -55,7 +55,7 @@ description: Add authentication and user management to your React app with Clerk ``` - ### Install `@clerk/clerk-react` + ## Install `@clerk/clerk-react` Clerk's [React SDK](/docs/references/react/overview) gives you access to prebuilt components, hooks, and helpers to make user authentication easier. @@ -75,7 +75,7 @@ description: Add authentication and user management to your React app with Clerk ``` - ### Set your Clerk API keys + ## Set your Clerk API keys Add your Clerk Publishable Key to your `.env.local` file. It can always be retrieved from the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page in the Clerk Dashboard. @@ -93,7 +93,7 @@ description: Add authentication and user management to your React app with Clerk VITE_CLERK_PUBLISHABLE_KEY={{pub_key}} ``` - ### Import the Clerk Publishable Key + ## Import the Clerk Publishable Key In your `main.tsx` file, import your Clerk Publishable Key. You can add an `if` statement to check that it is imported and that it exists. This will prevent running the app without the Publishable Key, and will also prevent TypeScript errors. @@ -117,7 +117,7 @@ description: Add authentication and user management to your React app with Clerk ) ``` - ### Add `` to your app + ## Add `` to your app @@ -146,7 +146,7 @@ description: Add authentication and user management to your React app with Clerk ) ``` - ### Create a header with Clerk components + ## Create a header with Clerk components You can control which content signed-in and signed-out users can see with the [prebuilt control components](/docs/components/overview#what-are-control-components). The following example creates a header using the following components: @@ -172,7 +172,7 @@ description: Add authentication and user management to your React app with Clerk } ``` - ### Create your first user + ## Create your first user Run your project with the following command: diff --git a/docs/quickstarts/remix.mdx b/docs/quickstarts/remix.mdx index 419f7fa983..7b7909a905 100644 --- a/docs/quickstarts/remix.mdx +++ b/docs/quickstarts/remix.mdx @@ -38,7 +38,7 @@ Learn how to use Clerk to quickly and easily add secure authentication and user > If you are using Remix SPA mode, follow the [Remix SPA mode guide](/docs/references/remix/spa-mode). - ### Install `@clerk/remix` + ## Install `@clerk/remix` Clerk's Remix SDK gives you access to prebuilt components, hooks, and helpers to make user authentication easier. @@ -58,7 +58,7 @@ Learn how to use Clerk to quickly and easily add secure authentication and user ``` - ### Set your Clerk API keys + ## Set your Clerk API keys Add the following keys to your `.env.local` file. These keys can always be retrieved from the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page in the Clerk Dashboard. @@ -77,7 +77,7 @@ Learn how to use Clerk to quickly and easily add secure authentication and user CLERK_SECRET_KEY={{secret}} ``` - ### Configure `rootAuthLoader` + ## Configure `rootAuthLoader` To configure Clerk in your Remix app, you will need to update your root loader. This will enable you to have access to authentication state in any Remix routes. @@ -138,7 +138,7 @@ Learn how to use Clerk to quickly and easily add secure authentication and user // Your additional app code ``` - ### Configure `ClerkApp` + ## Configure `ClerkApp` Clerk provides a `ClerkApp` wrapper to provide the authentication state to your React tree. This helper works with Remix SSR out-of-the-box and follows the "higher-order component" paradigm. @@ -186,9 +186,9 @@ Learn how to use Clerk to quickly and easily add secure authentication and user export default ClerkApp(App) ``` - ### Protect your pages + ## Protect your pages - #### Client-side + ### Client-side To protect your pages on the client-side, Clerk's [prebuilt control components](/docs/components/overview) control the visibility of content based on the user's authentication state. @@ -228,7 +228,7 @@ Learn how to use Clerk to quickly and easily add secure authentication and user } ``` - #### Server-side + ### Server-side To protect your routes, use the [`getAuth()`](/docs/references/nextjs/get-auth) function in your loader. This function retrieves the authentication state from the request object, returning an `Auth` object that includes the `userId`, allowing you to determine if the user is authenticated. @@ -256,7 +256,7 @@ Learn how to use Clerk to quickly and easily add secure authentication and user } ``` - ### Create your first user + ## Create your first user Run your project with the following command: diff --git a/docs/quickstarts/setup-clerk.mdx b/docs/quickstarts/setup-clerk.mdx index c3c056b1bd..6e22ce4582 100644 --- a/docs/quickstarts/setup-clerk.mdx +++ b/docs/quickstarts/setup-clerk.mdx @@ -9,23 +9,23 @@ Before you can start integrating Clerk into your application, you need to create > If you're migrating from another platform, see the [migration guides](/docs/deployments/migrate-overview) to learn how to move your data to Clerk. - ### Sign into Clerk + ## Sign into Clerk [Create a Clerk account](https://dashboard.clerk.com/sign-up) or [sign into the Clerk Dashboard](https://dashboard.clerk.com/). - ### Create a Clerk application + ## Create a Clerk application If you've just created an account for the first time, you'll be taken directly to the interactive authentication setup form. Otherwise, you'll be redirected to the [Clerk Dashboard](https://dashboard.clerk.com/). To create a new app, select the **Create application** card. You'll be redirected to the interactive authentication setup form. - ### Select identifiers and social providers + ## Select identifiers and social providers Once you are in the interactive authentication setup form, you will be asked to build your authentication flow. Here, Clerk provides various options for setting up your sign-up and sign-in flows. You can choose to use email, phone, or username as [identifiers](/docs/authentication/configuration/sign-up-sign-in-options#identifiers), and you can enable [social authentication providers](/docs/authentication/social-connections/overview). Once the application is created, you can also customize your authentication flow by selecting different authentication strategies, verification methods, and more. [Learn more about sign-up and sign-in options](/docs/authentication/configuration/sign-up-sign-in-options). - ### Integrate Clerk into your application + ## Integrate Clerk into your application Now that your application is created in the Clerk Dashboard, you can integrate it into your codebase. To integrate Clerk into your application, use one of our [quickstarts](/docs/quickstarts/overview): diff --git a/docs/quickstarts/tanstack-start.mdx b/docs/quickstarts/tanstack-start.mdx index 909bb5bc3e..0490284dca 100644 --- a/docs/quickstarts/tanstack-start.mdx +++ b/docs/quickstarts/tanstack-start.mdx @@ -31,7 +31,7 @@ description: Learn how to use Clerk to quickly and easily add secure authenticat - ### Install `@clerk/tanstack-start` + ## Install `@clerk/tanstack-start` Clerk's [TanStack Start SDK](/docs/references/tanstack-start/overview) gives you access to prebuilt components, React hooks, and helpers to make user authentication easier. @@ -51,7 +51,7 @@ description: Learn how to use Clerk to quickly and easily add secure authenticat ``` - ### Set your Clerk API keys + ## Set your Clerk API keys Add the following keys to your `.env` file. These keys can always be retrieved from the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page in the Clerk Dashboard. @@ -70,7 +70,7 @@ description: Learn how to use Clerk to quickly and easily add secure authenticat CLERK_SECRET_KEY={{secret}} ``` - ### Add `createClerkHandler()` + ## Add `createClerkHandler()` TanStack's [`createStartHandler()`](https://tanstack.com/router/latest/docs/framework/react/start/getting-started#the-server-entry-point) creates a server-side handler that determines which routes and loaders need to be executed when the user hits a given route. @@ -92,7 +92,7 @@ description: Learn how to use Clerk to quickly and easily add secure authenticat )(defaultStreamHandler) ``` - ### Add `` to your app + ## Add `` to your app @@ -132,9 +132,9 @@ description: Learn how to use Clerk to quickly and easily add secure authenticat } ``` - ### Protect your pages + ## Protect your pages - #### Client-side + ### Client-side To protect your pages on the client-side, you can use Clerk's [prebuilt control components](/docs/components/overview#what-are-control-components) that control the visibility of content based on the user's authentication state. @@ -177,7 +177,7 @@ description: Learn how to use Clerk to quickly and easily add secure authenticat } ``` - #### Server-side + ### Server-side To protect your routes, create a [server function](https://tanstack.com/router/latest/docs/framework/react/start/server-functions) that checks the user's authentication state via the [`getAuth()`](/docs/references/tanstack-start/get-auth) method. If the user is not authenticated, they are redirected to a sign-in page. If authenticated, the user's `userId` is passed to the route, allowing access to the `` component, which welcomes the user and displays their `userId`. The [`beforeLoad()`](https://tanstack.com/router/latest/docs/framework/react/api/router/RouteOptionsType#beforeload-method) method ensures authentication is checked before loading the page, and the [`loader()`](https://tanstack.com/router/latest/docs/framework/react/api/router/RouteOptionsType#loader-method) method returns the user data for use in the component. @@ -219,7 +219,7 @@ description: Learn how to use Clerk to quickly and easily add secure authenticat } ``` - ### Create your first user + ## Create your first user Run your project with the following command: diff --git a/docs/references/astro/react.mdx b/docs/references/astro/react.mdx index 38eeb6e23e..eb54d976b5 100644 --- a/docs/references/astro/react.mdx +++ b/docs/references/astro/react.mdx @@ -8,7 +8,7 @@ Astro provides an [integration](https://docs.astro.build/en/guides/integrations- If you have not set up your Astro application to work with Clerk, see the [quickstart guide](/docs/quickstarts/astro). - ### Install `@astrojs/react` + ## Install `@astrojs/react` Add the [Astro React integration](https://docs.astro.build/en/guides/integrations-guide/react/) to your project: @@ -26,7 +26,7 @@ If you have not set up your Astro application to work with Clerk, see the [quick ``` - ### Update `astro.config.mjs` + ## Update `astro.config.mjs` Add Clerk and React integrations to your Astro configuration: @@ -43,11 +43,11 @@ If you have not set up your Astro application to work with Clerk, see the [quick }) ``` - ### Use Clerk components + ## Use Clerk components You can use the [prebuilt components](/docs/components/overview) in your Astro pages or regular React components. - #### Astro pages + ### Astro pages The following example demonstrates how to use Clerk components in Astro pages. @@ -81,7 +81,7 @@ If you have not set up your Astro application to work with Clerk, see the [quick ``` - #### React components + ### React components The following example demonstrates how to use Clerk components in React components. @@ -103,7 +103,7 @@ If you have not set up your Astro application to work with Clerk, see the [quick } ``` - ### Use stores in your React components + ## Use stores in your React components Clerk Astro provides a set of useful [stores](/docs/references/astro/overview#client-side-helpers) that give you access to the [`Clerk`](/docs/references/javascript/clerk/clerk){{ target: '_blank' }} object, and helper methods for signing in and signing up. diff --git a/docs/references/chrome-extension/add-react-router.mdx b/docs/references/chrome-extension/add-react-router.mdx index f50eec3a12..f678523a09 100644 --- a/docs/references/chrome-extension/add-react-router.mdx +++ b/docs/references/chrome-extension/add-react-router.mdx @@ -32,7 +32,7 @@ description: Learn how to add React Router to your React app using their Data AP This tutorial demonstrates how to integrate React Router into your Chrome Extension application using the [Data API router](https://reactrouter.com/en/main/routers/picking-a-router#using-v64-data-apis). - ### Install `react-router-dom` + ## Install `react-router-dom` React Router is a lightweight, fully-featured routing library. To install it in your project, run the following command: @@ -43,7 +43,7 @@ This tutorial demonstrates how to integrate React Router into your Chrome Extens > [!IMPORTANT] > This guide assumes you're using Plasmo to build your Chrome Extension, so you must use `pnpm` as your package manager. - ### Create routes + ## Create routes 1. In the `src/` directory, create a `popup/` directory. 1. In the `popup/` directory, create a `routes/` directory. @@ -101,7 +101,7 @@ This tutorial demonstrates how to integrate React Router into your Chrome Extens ``` - ### Create layouts + ## Create layouts 1. Delete your `src/popup.tsx` file. 1. In your `src/popup/` directory, create a `layouts/` directory. @@ -153,7 +153,7 @@ This tutorial demonstrates how to integrate React Router into your Chrome Extens ``` - ### Configure layouts and routes with `createMemoryRouter` + ## Configure layouts and routes with `createMemoryRouter` [React Router's `createMemoryRouter`](https://reactrouter.com/en/main/routers/create-memory-router) is a router that uses memory to store the state of the router instead of the browser's history. This is useful for creating a router in a non-browser environment like a Chrome Extension. @@ -192,7 +192,7 @@ This tutorial demonstrates how to integrate React Router into your Chrome Extens } ``` - ### Test the integration + ## Test the integration 1. Run your project with the following command: ```bash {{ filename: 'terminal' }} diff --git a/docs/references/chrome-extension/sync-host.mdx b/docs/references/chrome-extension/sync-host.mdx index f00e995923..547c22ecba 100644 --- a/docs/references/chrome-extension/sync-host.mdx +++ b/docs/references/chrome-extension/sync-host.mdx @@ -12,7 +12,7 @@ Clerk allows you to sync the authentication state from your web app to your Chro > This guide assumes assumes that you have followed the [Chrome Extension Quickstart](/docs/quickstarts/chrome-extension) and then the [Add React Router](/docs/references/chrome-extension/add-react-router) guide. - ### Add `PLASMO_PUBLIC_CLERK_SYNC_HOST` to your environment variables + ## Add `PLASMO_PUBLIC_CLERK_SYNC_HOST` to your environment variables The `PLASMO_PUBLIC_CLERK_SYNC_HOST` environment variable defines the host that the Chrome Extension will sync with. @@ -42,7 +42,7 @@ Clerk allows you to sync the authentication state from your web app to your Chro - ### Add `syncHost` prop to your `` + ## Add `syncHost` prop to your `` Add the `syncHost` prop to your Chrome Extension's `` component. This prop tells the `` which host to sync with. @@ -91,7 +91,7 @@ Clerk allows you to sync the authentication state from your web app to your Chro } ``` - ### Configure `host_permissions` + ## Configure `host_permissions` `host_permissions` specifies which hosts, or websites, will have permission to sync auth state with your app. It accepts an array, allowing you to add more than one host. @@ -108,7 +108,7 @@ Clerk allows you to sync the authentication state from your web app to your Chro } ``` - ### Add the Extension's ID to your web app's `allowed_origins` + ## Add the Extension's ID to your web app's `allowed_origins` To allow your Chrome Extension to sync with your web app, you must add the extension's ID to your web app's `allowed_origins`. diff --git a/docs/references/expo/local-credentials.mdx b/docs/references/expo/local-credentials.mdx index ecd1ce0080..7c3b8f43ff 100644 --- a/docs/references/expo/local-credentials.mdx +++ b/docs/references/expo/local-credentials.mdx @@ -12,7 +12,7 @@ This guide shows you how to use the `useLocalCredentials()` hook to enhance your > Be aware that this works only for sign in attempts with the password strategy. - ### Install the necessary peer dependencies + ## Install the necessary peer dependencies These packages are required to be installed in order to use the `useLocalCredentials()` hook. @@ -30,14 +30,14 @@ This guide shows you how to use the `useLocalCredentials()` hook to enhance your ``` - ### Update `app.json` + ## Update `app.json` Update your app.json file as instructed in the Expo documentation: - [`expo-local-authentication`](https://docs.expo.dev/versions/latest/sdk/local-authentication/#configuration-in-appjsonappconfigjs) - [`expo-secure-store`](https://docs.expo.dev/versions/latest/sdk/securestore/#configuration-in-appjsonappconfigjs) - ### Securely store/access the user's credentials during sign in + ## Securely store/access the user's credentials during sign in The following example demonstrates how to use `useLocalCredentials()` in a custom flow for signing users in. @@ -113,7 +113,7 @@ This guide shows you how to use the `useLocalCredentials()` hook to enhance your } ``` - ### Delete credentials while user is logged in + ## Delete credentials while user is logged in The following example demonstrates how to use the `userOwnsCredentials` and `clearCredentials` properties of the `useLocalCredentials()` hook in order to remove the stored credentials if those belong to the signed in user. @@ -139,7 +139,7 @@ This guide shows you how to use the `useLocalCredentials()` hook to enhance your } ``` - ### Update credentials while user is logged in + ## Update credentials while user is logged in The following example demonstrates how to use `userOwnsCredentials` and `setCredentials` properties of the `useLocalCredentials()` hook in order to update the stored credentials if those belong to the signed in user. diff --git a/docs/references/expo/web-support/custom-signup-signin-pages.mdx b/docs/references/expo/web-support/custom-signup-signin-pages.mdx index 5890a38cdf..e0d47a0dd1 100644 --- a/docs/references/expo/web-support/custom-signup-signin-pages.mdx +++ b/docs/references/expo/web-support/custom-signup-signin-pages.mdx @@ -8,7 +8,7 @@ This guide shows you how to use the [``](/docs/components/authenticati This guide uses [Expo Router](https://docs.expo.dev/router/introduction/) and the [platform-specific extensions](https://docs.expo.dev/router/create-pages/#platform-specific-extensions) to build the sign-up and sign-in pages specifically for the **web** platform. - ### Build a sign-up page + ## Build a sign-up page The following example demonstrates how to render the [``](/docs/components/authentication/sign-up) component. @@ -20,7 +20,7 @@ This guide uses [Expo Router](https://docs.expo.dev/router/introduction/) and th } ``` - ### Build a sign-in page + ## Build a sign-in page The following example demonstrates how to render the [``](/docs/components/authentication/sign-in) component. @@ -32,7 +32,7 @@ This guide uses [Expo Router](https://docs.expo.dev/router/introduction/) and th } ``` - ### Visit your new pages + ## Visit your new pages To run your project, use the following command: diff --git a/docs/references/ios/sign-in-with-apple.mdx b/docs/references/ios/sign-in-with-apple.mdx index 6828cfb4cc..ae407fae2e 100644 --- a/docs/references/ios/sign-in-with-apple.mdx +++ b/docs/references/ios/sign-in-with-apple.mdx @@ -9,15 +9,15 @@ description: Learn how to use Clerk to natively Sign in with Apple. This guide will teach you how to add native Sign in with Apple to your Clerk apps on Apple platforms. - ### Configure the Apple social connection + ## Configure the Apple social connection To support native Sign in with Apple, you need to configure the Apple social connection in the Clerk Dashboard. To do so, follow the **native-specific instructions** in the [OAuth with Apple guide](/docs/authentication/social-connections/apple). - ### Add the Sign in with Apple capability to your app + ## Add the Sign in with Apple capability to your app [Add the Sign in with Apple capability to your app](https://developer.apple.com/documentation/xcode/configuring-sign-in-with-apple#Add-the-Sign-in-with-Apple-capability-to-your-app). - ### Obtain an Apple ID Credential + ## Obtain an Apple ID Credential To authenticate with Apple and Clerk, you need to obtain an [Apple ID Credential](https://developer.apple.com/documentation/authenticationservices/asauthorizationappleidcredential). @@ -29,7 +29,7 @@ This guide will teach you how to add native Sign in with Apple to your Clerk app > [!NOTE] > You must set the nonce property of the `ASAuthorizationAppleIDRequest` when requesting an Apple ID Credential in order to authenticate with Clerk. - ### Build your sign-in flow + ## Build your sign-in flow Once you have obtained your [Apple ID Credential](https://developer.apple.com/documentation/authenticationservices/asauthorizationappleidcredential), you can use it to authenticate with Clerk by calling [`SignIn.create(strategy:)`](https://swiftpackageindex.com/clerk/clerk-ios/main/documentation/clerksdk/signin/create\(strategy:\)) with a strategy of `.idToken` followed by `.authenticateWithIdToken()`. diff --git a/docs/references/nextjs/custom-signup-signin-pages.mdx b/docs/references/nextjs/custom-signup-signin-pages.mdx index 14a2899bb8..6b971df480 100644 --- a/docs/references/nextjs/custom-signup-signin-pages.mdx +++ b/docs/references/nextjs/custom-signup-signin-pages.mdx @@ -13,10 +13,8 @@ If the prebuilt components don't meet your specific needs or if you require more > [!NOTE] > Just getting started with Clerk and Next.js? See the [quickstart tutorial](/docs/quickstarts/nextjs)! -{/* TODO: Update these Steps once Steps component accepts other headings types. These headings should be H2s. */} - - ### Build a sign-up page + ## Build a sign-up page The following example demonstrates how to render the [``](/docs/components/authentication/sign-up) component. @@ -28,7 +26,7 @@ If the prebuilt components don't meet your specific needs or if you require more } ``` - ### Build a sign-in page + ## Build a sign-in page The following example demonstrates how to render the [``](/docs/components/authentication/sign-in) component. @@ -40,7 +38,7 @@ If the prebuilt components don't meet your specific needs or if you require more } ``` - ### Make the sign-up and sign-in routes public + ## Make the sign-up and sign-in routes public By default, `clerkMiddleware()` makes all routes public. **This step is specifically for applications that have configured `clerkMiddleware()` to make [all routes protected](/docs/references/nextjs/clerk-middleware#protect-all-routes).** If you have not configured `clerkMiddleware()` to protect all routes, you can skip this step. @@ -71,7 +69,7 @@ If the prebuilt components don't meet your specific needs or if you require more } ``` - ### Update your environment variables + ## Update your environment variables Update your environment variables to point to your custom sign-in and sign-up pages. Learn more about the available [environment variables](/docs/deployments/clerk-environment-variables). @@ -80,7 +78,7 @@ If the prebuilt components don't meet your specific needs or if you require more NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up ``` - ### Visit your new pages + ## Visit your new pages Run your project with the following command: diff --git a/docs/references/nextjs/trpc.mdx b/docs/references/nextjs/trpc.mdx index a8a7056a56..941b53f608 100644 --- a/docs/references/nextjs/trpc.mdx +++ b/docs/references/nextjs/trpc.mdx @@ -27,7 +27,7 @@ description: Learn how to integrate Clerk into your Next.js Pages Router applica - ### Create Clerk authentication context + ## Create Clerk authentication context Clerk's [`Auth`](/docs/references/nextjs/auth-object) object includes important authentication information like the current user's session ID, user ID, and organization ID. It also contains methods to check for the current user's permissions and to retrieve their session token. @@ -45,7 +45,7 @@ description: Learn how to integrate Clerk into your Next.js Pages Router applica export type Context = trpc.inferAsyncReturnType ``` - ### Create tRPC context + ## Create tRPC context Create the tRPC context to use the Clerk context in your tRPC queries. @@ -60,7 +60,7 @@ description: Learn how to integrate Clerk into your Next.js Pages Router applica }) ``` - ### Access the context data in your backend + ## Access the context data in your backend The tRPC context, or `ctx`, should now have access to the Clerk authentication context. Use `ctx` in your queries to access the context data in any procedure. @@ -78,7 +78,7 @@ description: Learn how to integrate Clerk into your Next.js Pages Router applica }) ``` - ### Create a protected procedure + ## Create a protected procedure In many applications, it's essential to restrict access to certain routes based on user authentication status. This ensures that sensitive data and functionality are only accessible to authorized users. tRPC middleware provides a powerful mechanism for implementing this protection within your application. @@ -116,7 +116,7 @@ description: Learn how to integrate Clerk into your Next.js Pages Router applica export const protectedProcedure = t.procedure.use(isAuthed) ``` - ### Use your protected procedure + ## Use your protected procedure Once you have created your procedure, you can use it in any router. diff --git a/docs/references/nextjs/usage-with-older-versions.mdx b/docs/references/nextjs/usage-with-older-versions.mdx index d5235b44c8..bb70cdf8ea 100644 --- a/docs/references/nextjs/usage-with-older-versions.mdx +++ b/docs/references/nextjs/usage-with-older-versions.mdx @@ -9,7 +9,7 @@ Clerk's [prebuilt components](/docs/components/overview) are exported from the ` > Clerk highly recommends updating your Next.js version as older versions won't receive any updates in the future. Read [their upgrade guides](https://nextjs.org/docs/pages/building-your-application/upgrading) to learn more. - ### Install `@clerk/nextjs` v4 + ## Install `@clerk/nextjs` v4 Install `^4.0.0` of `@clerk/nextjs`. Newer major versions of `@clerk/nextjs` only support Next.js 13+. @@ -27,7 +27,7 @@ Clerk's [prebuilt components](/docs/components/overview) are exported from the ` ``` - ### Change your `next.config.js` + ## Change your `next.config.js` As mentioned previously, the `@clerk/nextjs` components contain code for multiple Next.js versions, but depending on your version, only certain components will be used. Update your `next.config.js` to instruct webpack to ignore modules on code paths that won't be used. diff --git a/docs/references/react-router/custom-signup-signin-pages.mdx b/docs/references/react-router/custom-signup-signin-pages.mdx index 1bb6e01d6d..5a445e7093 100644 --- a/docs/references/react-router/custom-signup-signin-pages.mdx +++ b/docs/references/react-router/custom-signup-signin-pages.mdx @@ -8,7 +8,7 @@ This guide shows you how to use the [``](/docs/components/authenticati If the prebuilt components don't meet your specific needs or if you require more control over the logic, you can rebuild the existing Clerk flows using the Clerk API. For more information, see the [custom flow guides](/docs/custom-flows/overview). - ### Build a sign-up page + ## Build a sign-up page The following example demonstrates how to render the [``](/docs/components/authentication/sign-up) component. @@ -25,7 +25,7 @@ If the prebuilt components don't meet your specific needs or if you require more } ``` - ### Build a sign-in page + ## Build a sign-in page The following example demonstrates how to render the [``](/docs/components/authentication/sign-in) component. @@ -42,7 +42,7 @@ If the prebuilt components don't meet your specific needs or if you require more } ``` - ### Configure routes + ## Configure routes React Router expects you to define routes in [`app/routes.ts`](https://reactrouter.com/start/framework/routing). Add the previously created sign-in and sign-up pages to your route configuration. @@ -56,7 +56,7 @@ If the prebuilt components don't meet your specific needs or if you require more ] satisfies RouteConfig ``` - ### Configure redirect behavior + ## Configure redirect behavior Update your environment variables to point to your custom sign-up and sign-in pages. Learn more about the available [environment variables](/docs/deployments/clerk-environment-variables). @@ -69,7 +69,7 @@ If the prebuilt components don't meet your specific needs or if you require more These values control the behavior of the `` and `` components and when you visit the respective links at the bottom of each component. - ### Visit your new pages + ## Visit your new pages Run your project with the following command: diff --git a/docs/references/react-router/library-mode.mdx b/docs/references/react-router/library-mode.mdx index 87e57aef0f..4d04824993 100644 --- a/docs/references/react-router/library-mode.mdx +++ b/docs/references/react-router/library-mode.mdx @@ -30,7 +30,7 @@ description: Learn how to use Clerk with React Router in library mode to add aut React Router can be used as a framework or as a standalone library. This guide explains how to add React Router authentication to an existing React application using library mode. To use React Router as a framework instead, see the [React Router quickstart](/docs/quickstarts/react-router). - ### Install `@clerk/react-router` + ## Install `@clerk/react-router` Clerk's [React Router SDK](/docs/references/react-router/overview) provides prebuilt components, hooks, and stores to make it easy to integrate authentication and user management in your React Router app. @@ -50,7 +50,7 @@ React Router can be used as a framework or as a standalone library. This guide e ``` - ### Set your Clerk API keys + ## Set your Clerk API keys > [!NOTE] > You will not need the Clerk Secret Key in React Router's library mode, as it should never be used on the client-side. @@ -71,7 +71,7 @@ React Router can be used as a framework or as a standalone library. This guide e VITE_CLERK_PUBLISHABLE_KEY={{pub_key}} ``` - ### Add `` to your app + ## Add `` to your app @@ -100,7 +100,7 @@ React Router can be used as a framework or as a standalone library. This guide e ) ``` - ### Create a header with Clerk components + ## Create a header with Clerk components You can control which content signed-in and signed-out users can see with the [prebuilt control components](/docs/components/overview#what-are-control-components). The following example creates a header using the following components: diff --git a/docs/references/redwood/overview.mdx b/docs/references/redwood/overview.mdx index 02fcd94e68..7c2d5837b7 100644 --- a/docs/references/redwood/overview.mdx +++ b/docs/references/redwood/overview.mdx @@ -6,7 +6,7 @@ description: Learn how to use Clerk to quickly and easily add secure authenticat Learn how to use Clerk to quickly and easily add secure authentication and user management to your RedwoodJS application. - ### Create a RedwoodJS application + ## Create a RedwoodJS application ```bash {{ filename: 'terminal' }} @@ -22,7 +22,7 @@ Learn how to use Clerk to quickly and easily add secure authentication and user ``` - ### Set environment variables + ## Set environment variables Below is an example of an `.env.local` file. @@ -33,14 +33,14 @@ Learn how to use Clerk to quickly and easily add secure authentication and user CLERK_SECRET_KEY={{secret}} ``` - #### Update redwood.toml + ### Update redwood.toml ```toml {{ filename: 'redwood.toml' }} [web] includeEnvironmentVariables = ['CLERK_PUBLISHABLE_KEY'] ``` - ### Set up Redwood auth + ## Set up Redwood auth The next step is to run a Redwood CLI command to install the required packages and generate some boilerplate code: @@ -53,7 +53,7 @@ Learn how to use Clerk to quickly and easily add secure authentication and user You can now access Clerk functions through the Redwood `useAuth()` hook, which is exported from `src/web/auth.tsx`, or you can use the Clerk components directly. - ### Protecting your pages + ## Protecting your pages Below is an example of using the `useAuth()` hook to verify if the user is authenticated. This will open a modal for your user to sign in to their account. @@ -80,7 +80,7 @@ Learn how to use Clerk to quickly and easily add secure authentication and user export default HomePage ``` - ### Using Clerk components directly + ## Using Clerk components directly ```tsx {{ filename: 'index.tsx' }} import { SignInButton, UserButton } from '@clerk/clerk-react' @@ -105,7 +105,7 @@ Learn how to use Clerk to quickly and easily add secure authentication and user ``` -### Next steps +## Next steps Now that you have an application integrated with Clerk, you will want to read the following documentation: diff --git a/docs/references/remix/custom-signup-signin-pages.mdx b/docs/references/remix/custom-signup-signin-pages.mdx index f0a2cb40dd..3157c9702e 100644 --- a/docs/references/remix/custom-signup-signin-pages.mdx +++ b/docs/references/remix/custom-signup-signin-pages.mdx @@ -13,7 +13,7 @@ The functionality of the components are controlled by the instance settings you > Just getting started with Clerk and Remix? See the [quickstart tutorial](/docs/quickstarts/remix)! - ### Build your sign-up page + ## Build your sign-up page The following example demonstrates how to render the [``](/docs/components/authentication/sign-up) component. @@ -30,7 +30,7 @@ The functionality of the components are controlled by the instance settings you } ``` - ### Build your sign-in page + ## Build your sign-in page The following example demonstrates how to render the [``](/docs/components/authentication/sign-in) component. @@ -47,7 +47,7 @@ The functionality of the components are controlled by the instance settings you } ``` - ### Configure your sign-up and sign-in pages + ## Configure your sign-up and sign-in pages @@ -78,7 +78,7 @@ The functionality of the components are controlled by the instance settings you These values control the behavior of the components when you sign in or sign up and when you click on the respective links at the bottom of each component. - ### Visit your new pages + ## Visit your new pages Run your project with the following terminal command from the root directory of your project: diff --git a/docs/references/remix/spa-mode.mdx b/docs/references/remix/spa-mode.mdx index 3c92e3c79b..c0c6de3a04 100644 --- a/docs/references/remix/spa-mode.mdx +++ b/docs/references/remix/spa-mode.mdx @@ -25,7 +25,7 @@ description: Clerk supports Remix SPA mode out-of-the-box. > If you are using Remix with SSR, follow the [Remix quickstart](/docs/quickstarts/remix). - ### Install `@clerk/remix` + ## Install `@clerk/remix` Once you have a Remix application ready, you need to install Clerk's Remix SDK. This gives you access to our prebuilt components and hooks for Remix applications. @@ -43,7 +43,7 @@ description: Clerk supports Remix SPA mode out-of-the-box. ``` - ### Set your environment variables + ## Set your environment variables Add your Clerk Publishable Key to your `.env` file. It can always be retrieved from the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page in the Clerk Dashboard. @@ -64,7 +64,7 @@ description: Clerk supports Remix SPA mode out-of-the-box. VITE_CLERK_PUBLISHABLE_KEY={{pub_key}} ``` - ### Configure `ClerkApp` + ## Configure `ClerkApp` Clerk provides a `ClerkApp` wrapper to provide the authentication state to your React tree. @@ -98,7 +98,7 @@ description: Clerk supports Remix SPA mode out-of-the-box. }) ``` - ### Update your paths through ClerkApp options + ## Update your paths through ClerkApp options Next, add paths to your `ClerkApp` options to control the behavior of the components when you sign in or sign up and when you click on the respective links at the bottom of each component. @@ -110,7 +110,7 @@ description: Clerk supports Remix SPA mode out-of-the-box. }) ``` - ### Protecting your pages + ## Protecting your pages Clerk offers [Control Components](/docs/components/overview) that allow you to protect your pages. These components are used to control the visibility of your pages based on the user's authentication state. @@ -153,7 +153,7 @@ description: Clerk supports Remix SPA mode out-of-the-box. ``` -### Next steps +## Next steps Now that you have an application integrated with Clerk, you will want to read the following documentation: diff --git a/docs/references/ruby/overview.mdx b/docs/references/ruby/overview.mdx index 71b1475fe9..fb9b3491f7 100644 --- a/docs/references/ruby/overview.mdx +++ b/docs/references/ruby/overview.mdx @@ -4,11 +4,11 @@ description: Learn how to integrate Ruby into your Clerk application. --- - ### Create a Clerk application + ## Create a Clerk application You need to create a Clerk application in the Clerk Dashboard before you can set up Clerk Ruby. For more information, see the [setup guide](/docs/quickstarts/setup-clerk). - ### Install Ruby + ## Install Ruby Once a Clerk application has been created, you can install and then start using Clerk Ruby in your application. @@ -30,7 +30,7 @@ description: Learn how to integrate Ruby into your Clerk application. $ gem install clerk-sdk-ruby ``` - ### Instantiate a `Clerk::SDK` instance + ## Instantiate a `Clerk::SDK` instance To access all [Backend API endpoints](/docs/reference/backend-api){{ target: '_blank' }}, you need to instantiate a `Clerk::SDK` instance. @@ -59,7 +59,7 @@ description: Learn how to integrate Ruby into your Clerk application. ) ``` - ### Configuration + ## Configuration The SDK can be configured in three ways: environment variables, configuration singleton and constructor arguments. The priority goes like this: @@ -67,7 +67,7 @@ description: Learn how to integrate Ruby into your Clerk application. - Configuration object - Environment variables - #### Constructor arguments + ### Constructor arguments You can customize each instance of the `Clerk::SDK` object by passing keyword arguments to the constructor: @@ -79,7 +79,7 @@ description: Learn how to integrate Ruby into your Clerk application. ) ``` - #### Configuration object + ### Configuration object If an argument is not provided, the configuration object is looked up, which falls back to the associated environment variable. Here's an example with all supported configuration settings their environment variable equivalents: @@ -94,7 +94,7 @@ description: Learn how to integrate Ruby into your Clerk application. For more information, see [Faraday's documentation](https://lostisland.github.io/faraday/#/). - #### Environment variables + ### Environment variables Here's a list of all environment variables the SDK uses: diff --git a/docs/testing/cypress/overview.mdx b/docs/testing/cypress/overview.mdx index cf29c71c31..60c43969f2 100644 --- a/docs/testing/cypress/overview.mdx +++ b/docs/testing/cypress/overview.mdx @@ -14,7 +14,7 @@ This guide will help you set up your environment for creating Clerk-authenticate > Check out the [demo repo](https://github.com/clerk/clerk-cypress-nextjs) that tests a Clerk-powered application using [Testing Tokens](/docs/testing/overview#testing-tokens). - ### Install `@clerk/testing` + ## Install `@clerk/testing` Clerk's testing package provides integration helpers for popular testing frameworks. Run the following command to install it: @@ -32,7 +32,7 @@ This guide will help you set up your environment for creating Clerk-authenticate ``` - ### Set your API keys + ## Set your API keys In your test runner, set your Publishable and Secret Keys as the `CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY` environment variables, respectively. @@ -45,7 +45,7 @@ This guide will help you set up your environment for creating Clerk-authenticate > [!WARNING] > Ensure you provide the Secret Key in a secure manner, to avoid leaking it to third parties. For example, if you are using GitHub Actions, refer to [_Using secrets in GitHub Actions_](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions). - ### Global setup + ## Global setup To set up Clerk with Cypress, call the `clerkSetup()` function in your [`cypress.config.ts`](https://docs.cypress.io/guides/references/configuration) file. @@ -65,7 +65,7 @@ This guide will help you set up your environment for creating Clerk-authenticate `clerkSetup()` will retrieve a [Testing Token](/docs/testing/overview#testing-tokens) once the test suite starts, making it available for all subsequent tests. - ### Use Clerk Testing Tokens + ## Use Clerk Testing Tokens Now that Cypress is configured with Clerk, use the `setupClerkTestingToken()` function in your tests to integrate the Testing Token. See the following example: diff --git a/docs/testing/playwright/overview.mdx b/docs/testing/playwright/overview.mdx index db52bdaf37..dfa0dff650 100644 --- a/docs/testing/playwright/overview.mdx +++ b/docs/testing/playwright/overview.mdx @@ -9,7 +9,7 @@ description: Use Playwright to write end-to-end tests with Clerk. > See the [demo repo](https://github.com/clerk/clerk-playwright-nextjs) that demonstrates testing a Clerk-powered application using [Testing Tokens](/docs/testing/overview#testing-tokens). To run the tests, you'll need dev instance Clerk API keys, a test user with username and password, and have username and password authentication enabled in the Clerk Dashboard. - ### Install `@clerk/testing` + ## Install `@clerk/testing` Clerk's testing package provides integration helpers for popular testing frameworks. Run the following command to install it: @@ -27,7 +27,7 @@ description: Use Playwright to write end-to-end tests with Clerk. ``` - ### Set your API keys + ## Set your API keys In your test runner, set your Publishable and Secret Keys as the `CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY` environment variables, respectively. @@ -39,7 +39,7 @@ description: Use Playwright to write end-to-end tests with Clerk. > [!WARNING] > Ensure that the Secret Key is provided securely to prevent exposure to third parties. For example, if you are using GitHub Actions, refer to [_Using secrets in GitHub Actions_](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions). - ### Configure Playwright with Clerk + ## Configure Playwright with Clerk The `clerkSetup()` function obtains a Testing Token when your test suite starts, making it available for all subsequent tests to use. This ensures that you don't have to manually generate a Testing Token for each test. @@ -60,7 +60,7 @@ description: Use Playwright to write end-to-end tests with Clerk. > [!NOTE] > You can manually set the Testing Token by using the `CLERK_TESTING_TOKEN` environment variable instead of calling `clerkSetup()`. - ### Use `setupClerkTestingToken()` + ## Use `setupClerkTestingToken()` Now that Playwright is configured with Clerk, you can use the `setupClerkTestingToken()` function to include the Testing Token in individual test cases. This function injects the Testing Token for the specific test, ensuring the test can bypass Clerk's bot detection mechanisms. See the following example: diff --git a/docs/testing/playwright/test-authenticated-flows.mdx b/docs/testing/playwright/test-authenticated-flows.mdx index b3d1af2c4b..4c3054ef64 100644 --- a/docs/testing/playwright/test-authenticated-flows.mdx +++ b/docs/testing/playwright/test-authenticated-flows.mdx @@ -11,7 +11,7 @@ This guide demonstrates how to save the auth state globally and load it in your > See the [demo repo](https://github.com/clerk/clerk-playwright-nextjs) that demonstrates testing a Clerk-powered application using [Testing Tokens](/docs/testing/overview#testing-tokens). To run the tests, you'll need dev instance Clerk API keys, a test user with username and password, and have username and password authentication enabled in the Clerk Dashboard. - ### Create a storage directory + ## Create a storage directory Create a `playwright/.clerk` directory and add it to your `.gitignore`. Once the auth state is generated, it will be stored to a file in this directory. Later on, tests will reuse this state and start already authenticated. @@ -20,7 +20,7 @@ This guide demonstrates how to save the auth state globally and load it in your echo $'\nplaywright/.clerk' >> .gitignore ``` - ### Prepare auth state for your tests + ## Prepare auth state for your tests Authenticate and save the auth state in your [global setup file](https://playwright.dev/docs/test-global-setup-teardown). @@ -66,11 +66,11 @@ This guide demonstrates how to save the auth state globally and load it in your }) ``` - ### Load the stored auth state in your tests + ## Load the stored auth state in your tests You can either load the stored auth state [in the config](#-in-the-config) or directly [in a test file](#-in-a-test-file). Loading in the config is useful if you want to authenticate once and reuse the same auth state for all tests or groups of tests. Loading in a test file is useful if you want to authenticate for a specific test case. - #### In the config + ### In the config In your `playwright.config.ts`, create a `global setup` project and declare it as a [dependency](https://playwright.dev/docs/test-projects#dependencies) for all your testing projects. This means that the `global setup` project will always run before all the tests, and because it's where you prepared auth state, it will authenticate before all the tests. All testing projects should use the authenticated state as `storageState`. @@ -103,7 +103,7 @@ This guide demonstrates how to save the auth state globally and load it in your ] ``` - #### In a test file + ### In a test file To use the stored auth state in a test file, see the following example: diff --git a/docs/webhooks/loops.mdx b/docs/webhooks/loops.mdx index eae8cb1dc3..73bffcb29f 100644 --- a/docs/webhooks/loops.mdx +++ b/docs/webhooks/loops.mdx @@ -25,7 +25,7 @@ description: Learn how to add your Clerk users to your Loops audience, and send This tutorial demonstrates how to sync your Clerk users to Loops so you can email users with Loop's email marketing tools. You will also learn how to send email sequences to new Clerk users. - ### Create a Clerk webhook endpoint in Loops + ## Create a Clerk webhook endpoint in Loops Loops' [Incoming webhooks](https://loops.so/docs/integrations/incoming-webhooks) feature lets Loops accept webhooks directly from external platforms like Clerk. @@ -34,7 +34,7 @@ This tutorial demonstrates how to sync your Clerk users to Loops so you can emai 1. Navigate to the **Clerk** settings page in the [Loops dashboard](https://app.loops.so/settings?page=clerk). 1. Save the **Endpoint URL** somewhere secure; you're going to need it for Clerk's webhook configuration. - ### Create a webhook in the Clerk Dashboard + ## Create a webhook in the Clerk Dashboard You must create a new Clerk webhook endpoint so that it can send data to Loops. Here is where you will provide the **Endpoint URL** from the last step, and then choose the events you want to listen to. @@ -45,14 +45,14 @@ This tutorial demonstrates how to sync your Clerk users to Loops so you can emai 1. Select the **Create** button. 1. You will be redirected to your endpoint's settings page. Leave this page open. - ### Add your signing secret in Loops + ## Add your signing secret in Loops To keep communication secure between the two platforms: 1. On the Clerk endpoint's settings page, copy the **Signing Secret**. It should be on the right side of the page with an eye icon next to it. 1. Back in the Loops dashboard, add the **Signing Secret**. - ### Configure Loops events + ## Configure Loops events The final step is to configure which events Loops should accept from Clerk and what Loops should do with the data. diff --git a/docs/webhooks/sync-data.mdx b/docs/webhooks/sync-data.mdx index 7f6267e2c5..a7024f6bf3 100644 --- a/docs/webhooks/sync-data.mdx +++ b/docs/webhooks/sync-data.mdx @@ -39,7 +39,7 @@ Clerk offers many events, but three key events include: These steps apply to any Clerk event. To make the setup process easier, it's recommended to keep two browser tabs open: one for your Clerk [**Webhooks**](https://dashboard.clerk.com/last-active?path=webhooks) page and one for your [ngrok dashboard](https://dashboard.ngrok.com). - ### Set up ngrok + ## Set up ngrok To test a webhook locally, you need to expose your local server to the internet. This guide uses [ngrok](https://ngrok.com/) which creates a **forwarding URL** that sends the webhook payload to your local server. @@ -51,7 +51,7 @@ These steps apply to any Clerk event. To make the setup process easier, it's rec 1. Paste the command in your terminal and change the port number to match your server's port. For this guide, replace `80` with `3000`, then run the command in your terminal. It will generate a **Forwarding** URL. It should resemble `https://fawn-two-nominally.ngrok-free.app`. 1. Save your **Forwarding** URL somewhere secure. Close the panel. - ### Set up a webhook endpoint + ## Set up a webhook endpoint 1. In the Clerk Dashboard, navigate to the [**Webhooks**](https://dashboard.clerk.com/last-active?path=webhooks) page. 1. Select **Add Endpoint**. @@ -59,7 +59,7 @@ These steps apply to any Clerk event. To make the setup process easier, it's rec 1. In the **Subscribe to events** section, scroll down and select `user.created`. 1. Select **Create**. You'll be redirected to your endpoint's settings page. Keep this page open. - ### Add your Signing Secret to `.env.local` + ## Add your Signing Secret to `.env.local` To verify the webhook payload, you'll need your endpoint's **Signing Secret**. Since you don't want this secret exposed in your codebase, store it as an environment variable in your `.env.local` file during local development. @@ -72,11 +72,11 @@ These steps apply to any Clerk event. To make the setup process easier, it's rec SIGNING_SECRET=whsec_123 ``` - ### Set the webhook route as public in your Middleware + ## Set the webhook route as public in your Middleware Incoming webhook events don't contain auth information. They come from an external source and aren't signed in or out, so the route must be public to allow access. If you're using `clerkMiddleware()`, ensure that the `/api/webhooks(.*)` route is set as public. For information on configuring routes, see the [`clerkMiddleware()` guide](/docs/references/nextjs/clerk-middleware). - ### Install `svix` + ## Install `svix` Clerk uses [`svix`](https://www.npmjs.com/package/svix) to deliver webhooks, so you'll use it to verify the webhook signature. Run the following command in your terminal to install the package: @@ -94,7 +94,7 @@ These steps apply to any Clerk event. To make the setup process easier, it's rec ``` - ### Create the endpoint + ## Create the endpoint Set up a Route Handler that uses `svix` to verify the incoming Clerk webhook and process the payload. @@ -239,7 +239,7 @@ These steps apply to any Clerk event. To make the setup process easier, it's rec - ### Narrow to a webhook event for type inference + ## Narrow to a webhook event for type inference `WebhookEvent` encompasses all possible webhook types. Narrow down the event type for accurate typing for specific events. @@ -265,7 +265,7 @@ These steps apply to any Clerk event. To make the setup process easier, it's rec - `SMSMessageJSON` - `UserJSON` - ### Test the webhook + ## Test the webhook 1. Start your Next.js server. 1. In your endpoint's settings page in the Clerk Dashboard, select the **Testing** tab. @@ -273,14 +273,14 @@ These steps apply to any Clerk event. To make the setup process easier, it's rec 1. Select **Send Example**. 1. In the **Message Attempts** section, confirm that the event is labeled with `Succeeded`. - #### Handling failed messages + ### Handling failed messages 1. In the **Message Attempts** section, select the event labeled with `Failed`. 1. Scroll down to the **Webhook Attempts** section. 1. Toggle the arrow next to the **Status** column. 1. Review the error. Solutions vary by error type. For more information, refer to the [Debug your webhooks](/docs/webhooks/debug-your-webhooks) guide. - ### Trigger the webhook + ## Trigger the webhook To trigger the `user.created` event, you can do either one of the following: @@ -290,7 +290,7 @@ These steps apply to any Clerk event. To make the setup process easier, it's rec You should be able to see the webhook's payload logged to your terminal. You can also check the Clerk Dashboard to see the webhook attempt, the same way you did when [testing the webhook](#test-the-webhook). -### Configure your production instance +## Configure your production instance 1. When you're ready to deploy your app to production, follow [the guide on deploying your Clerk app to production](/docs/deployments/overview). 1. Create your production webhook by following the steps in the previous [Set up a webhook endpoint](#set-up-a-webhook-endpoint) section. In the **Endpoint URL** field, instead of pasting the ngrok URL, paste your production app URL. diff --git a/styleguides/SSO.STYLEGUIDE.MD b/styleguides/SSO.STYLEGUIDE.MD index d5dd940c85..24bd4998dd 100644 --- a/styleguides/SSO.STYLEGUIDE.MD +++ b/styleguides/SSO.STYLEGUIDE.MD @@ -38,7 +38,7 @@ These are the guidelines we use to write our SSO guides. - The `Test your OAuth` section should be included in the `` and formatted as follows: ```mdx - ### Test your OAuth + ## Test your OAuth The simplest way to test your OAuth is to visit your Clerk app's [Account Portal](/docs/customization/account-portal/overview), which is available for all Clerk apps out-of-the-box. From ce044c330bb2370978fdfdd3d0de680590f46736 Mon Sep 17 00:00:00 2001 From: Roy Anger Date: Thu, 12 Dec 2024 22:45:41 -0500 Subject: [PATCH 34/36] feat: Add faq section to help address some common questions (#1771) Co-authored-by: vi --- docs/references/chrome-extension/overview.mdx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/references/chrome-extension/overview.mdx b/docs/references/chrome-extension/overview.mdx index 2f2ba6ffd8..992d897d24 100644 --- a/docs/references/chrome-extension/overview.mdx +++ b/docs/references/chrome-extension/overview.mdx @@ -52,3 +52,19 @@ See [the Chrome Extension deployment guide](/docs/deployments/deploy-chrome-exte ## Configure a consistent CRX ID A Chrome Extension can be identified by its unique CRX ID, similar to how a website can be identified by its domain. The CRX ID rotates by default, which can cause errors with the Clerk integration. [Learn how to configure a consistent CRX ID](/docs/references/chrome-extension/configure-consistent-crx-id) so that your extension will have a stable, unchanging key. + +## Frequently asked questions (FAQ) + +### Can I use Clerk in a content script? + +Unfortunately, no. Clerk has strict security restrictions on the allowed origins for requests from the application or extension to Clerk's API. Since a content script could run on any domain, there is no way to enforce origin restrictions. + +### Why can't I use OAuth, SAML, or Email Links with the extension popup or side panel? + +OAuth and SAML require a redirect back from the Identity Provider (IdP), which is not currently supported in popups or side panels. + +Email Links require the popup to remain open while the user checks their email, copies the link, and returns to paste it. Since popups close as soon as a user clicks outside of them, this flow is not possible. The sign-in status resets when the popup closes. + +### Why aren't options like Google One Tap or Web3 available in a popup or side panel? + +Chrome Extensions can't load code from remote sources. Features like Google One Tap, Web3, and some other authentication options require loading remote code to function. This functionality is removed from the Chrome Extension SDK to ensure extensions using Clerk are not rejected by the Chrome Web Store. From 93b0cd943c5aacd345e2a346090287c315d2c152 Mon Sep 17 00:00:00 2001 From: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> Date: Fri, 13 Dec 2024 11:09:39 -0500 Subject: [PATCH 35/36] (enterprise-connections/overview) remove info about pricing (#1802) --- docs/authentication/enterprise-connections/overview.mdx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/authentication/enterprise-connections/overview.mdx b/docs/authentication/enterprise-connections/overview.mdx index 5a8df7cb68..db77f71d6a 100644 --- a/docs/authentication/enterprise-connections/overview.mdx +++ b/docs/authentication/enterprise-connections/overview.mdx @@ -47,7 +47,7 @@ It is ultimately the app's responsibility to handle this unauthenticated state a ### SAML vs. EASIE -The primary security difference between EASIE SSO and SAML SSO is that EASIE depends on a multi-tenant identity provider, while SAML depends on a single-tenant identity provider. Relying on a multi-tenant provider **increases** the risk that a user from one tenant will mistakenly be granted access to the resources of another tenant. While Clerk implements [measures to address this risk](https://easie.dev/#mitigating-tenant-crossover-vulnerabilities), apps that require single-tenant IdPs should opt for SAML. +The primary security difference between EASIE SSO and SAML SSO is that EASIE depends on a multi-tenant identity provider, while SAML depends on a single-tenant identity provider. Relying on a multi-tenant provider **increases** the risk that a user from one tenant will mistakenly be granted access to the resources of another tenant. While Clerk implements [measures to address this risk](https://easie.dev/#mitigating-tenant-crossover-vulnerabilities:~:text=4.%20Mitigating%20tenant%20crossover%20vulnerabilities), apps that require single-tenant IdPs should opt for SAML. For more information, see the [EASIE docs](https://easie.dev#security). @@ -78,7 +78,3 @@ Yes, for SAML only. Clerk supports both Service Provider-initiated (SP-initiated For development instances, Enterprise connections are always free but limited to a maximum of 25. Production instances require the Pro plan and the Enhanced Authentication Add-on. Please see [pricing](/pricing){{ target: '_blank' }} for more information. - -### Can I get a bulk discount? - -Yes, [contact support](/contact/support){{ target: '_blank' }} to work out a custom plan. From 3ee5b0657c0ccacd78ea35f1bdce53d8b53510a9 Mon Sep 17 00:00:00 2001 From: Mike Wickett Date: Fri, 13 Dec 2024 11:11:34 -0500 Subject: [PATCH 36/36] remove old api-keys doc (#1804) --- docs/upgrade-guides/api-keys.mdx | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 docs/upgrade-guides/api-keys.mdx diff --git a/docs/upgrade-guides/api-keys.mdx b/docs/upgrade-guides/api-keys.mdx deleted file mode 100644 index 67bb9cb24a..0000000000 --- a/docs/upgrade-guides/api-keys.mdx +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: Publishable and Secret Keys -description: Dive into Clerk's latest V3 update. ---- - -> [!NOTE] -> If your application was created after January 18, 2023, you're already using Publishable and Secret Keys. - -In early Clerk SDKs, developers were required to configure three keys: - -- Frontend API URL -- API key -- JWT key (depending on the SDK version) - -New SDKs have replaced these with two keys: - -- Publishable Key (prefixed with `pk_test_` or `pk_live_`) -- Secret Key (prefixed with `sk_test_` or `sk_live_`) - -The name and format of these keys are common among developer tools, and we adopted them to provide a more familiar developer experience. - -Although legacy keys will remain operational, we have updated our documentation and code samples to use the new Publishable Key and Secret Key format. - -> [!CAUTION] -> Legacy keys cannot be mixed with the new Publishable and Secret Keys. It is important that you replace all keys at once. - -We recommend updating at your earliest convenience.