[{"data":1,"prerenderedAt":826},["ShallowReactive",2],{"navigation_docs":3,"-oauth-sign-in-with-sporty":224,"-oauth-sign-in-with-sporty-surround":821},[4,157,184],{"title":5,"path":6,"stem":7,"children":8,"page":156},"Interface","\u002Finterface","1.interface",[9,53,61,68,75,82,90,97,104,111,132,139,145],{"title":10,"path":11,"stem":12,"children":13,"icon":15},"Courts","\u002Finterface\u002Fcourts","1.interface\u002F01.courts\u002F1.index",[14,16],{"title":10,"path":11,"stem":12,"icon":15},"sporty-court-sport",{"title":17,"path":18,"stem":19,"children":20,"icon":22},"Access control and lights","\u002Finterface\u002Fcourts\u002Fintegrations","1.interface\u002F01.courts\u002F5.integrations\u002F1.index",[21,23,28,33],{"title":17,"path":18,"stem":19,"icon":22},"sporty-toggle-large-on",{"title":24,"path":25,"stem":26,"icon":27},"Weblock","\u002Finterface\u002Fcourts\u002Fintegrations\u002Fweblock","1.interface\u002F01.courts\u002F5.integrations\u002F2.weblock","sporty-door-open",{"title":29,"path":30,"stem":31,"icon":32},"Shelly","\u002Finterface\u002Fcourts\u002Fintegrations\u002Fshelly","1.interface\u002F01.courts\u002F5.integrations\u002F3.shelly","sporty-bolt",{"title":34,"path":35,"stem":36,"children":37,"icon":27},"UniFi Access","\u002Finterface\u002Fcourts\u002Fintegrations\u002Funifi-access","1.interface\u002F01.courts\u002F5.integrations\u002F4.unifi-access\u002F1.index",[38,40,44,49],{"title":39,"path":35,"stem":36,"icon":27},"Overview",{"title":41,"path":42,"stem":43,"icon":22},"Connect the VPN","\u002Finterface\u002Fcourts\u002Fintegrations\u002Funifi-access\u002Fvpn","1.interface\u002F01.courts\u002F5.integrations\u002F4.unifi-access\u002F2.vpn",{"title":45,"path":46,"stem":47,"icon":48},"Create an API token","\u002Finterface\u002Fcourts\u002Fintegrations\u002Funifi-access\u002Fapi-token","1.interface\u002F01.courts\u002F5.integrations\u002F4.unifi-access\u002F3.api-token","sporty-gear",{"title":50,"path":51,"stem":52,"icon":15},"Set it up in Club Admin","\u002Finterface\u002Fcourts\u002Fintegrations\u002Funifi-access\u002Fclub-admin","1.interface\u002F01.courts\u002F5.integrations\u002F4.unifi-access\u002F4.club-admin",{"title":54,"path":55,"stem":56,"children":57,"icon":60},"Members","\u002Finterface\u002Fmembers","1.interface\u002F02.members\u002F1.index",[58],{"title":59,"path":55,"stem":56,"icon":60},"Member management","sporty-user-group",{"title":62,"path":63,"stem":64,"children":65,"icon":67},"Memberships","\u002Finterface\u002Fmemberships","1.interface\u002F03.memberships\u002F1.index",[66],{"title":62,"path":63,"stem":64,"icon":67},"sporty-id-card",{"title":69,"path":70,"stem":71,"children":72,"icon":74},"Leagues","\u002Finterface\u002Fleagues","1.interface\u002F04.leagues\u002F1.index",[73],{"title":69,"path":70,"stem":71,"icon":74},"sporty-ranking-star",{"title":76,"path":77,"stem":78,"children":79,"icon":81},"Tournaments","\u002Finterface\u002Ftournaments","1.interface\u002F05.tournaments\u002F1.index",[80],{"title":76,"path":77,"stem":78,"icon":81},"sporty-trophy",{"title":83,"path":84,"stem":85,"children":86,"icon":89},"Payments and subscriptions","\u002Finterface\u002Fpayments","1.interface\u002F06.payments\u002F1.index",[87],{"title":88,"path":84,"stem":85,"icon":89},"Payments","sporty-credit-card",{"title":91,"path":92,"stem":93,"children":94,"icon":96},"Shop","\u002Finterface\u002Fshop","1.interface\u002F07.shop\u002F1.index",[95],{"title":91,"path":92,"stem":93,"icon":96},"sporty-bag-shopping",{"title":98,"path":99,"stem":100,"children":101,"icon":103},"Schools and coaches","\u002Finterface\u002Fschools","1.interface\u002F08.schools\u002F1.index",[102],{"title":98,"path":99,"stem":100,"icon":103},"sporty-graduation-cap",{"title":105,"path":106,"stem":107,"children":108,"icon":110},"Emails","\u002Finterface\u002Femails","1.interface\u002F09.emails\u002F1.index",[109],{"title":105,"path":106,"stem":107,"icon":110},"sporty-envelope",{"title":112,"path":113,"stem":114,"children":115,"icon":117},"Video and cameras","\u002Finterface\u002Fvideo","1.interface\u002F10.video\u002F1.index",[116,118,122,127],{"title":112,"path":113,"stem":114,"icon":117},"sporty-camera-cctv",{"title":119,"path":120,"stem":121,"icon":117},"Dahua cameras","\u002Finterface\u002Fvideo\u002Fdahua","1.interface\u002F10.video\u002F2.dahua",{"title":123,"path":124,"stem":125,"icon":126},"Other RTMP cameras","\u002Finterface\u002Fvideo\u002Frtmp","1.interface\u002F10.video\u002F3.rtmp","sporty-video",{"title":128,"path":129,"stem":130,"icon":131},"Match analytics","\u002Finterface\u002Fvideo\u002Fanalytics","1.interface\u002F10.video\u002F4.analytics","sporty-chart-simple",{"title":133,"path":134,"stem":135,"children":136,"icon":138},"Reports","\u002Finterface\u002Freports","1.interface\u002F11.reports\u002F1.index",[137],{"title":133,"path":134,"stem":135,"icon":138},"sporty-chart-mixed",{"title":140,"path":141,"stem":142,"children":143,"icon":48},"Settings","\u002Finterface\u002Fsettings","1.interface\u002F12.settings\u002F1.index",[144],{"title":140,"path":141,"stem":142,"icon":48},{"title":146,"path":147,"stem":148,"children":149,"icon":151},"Social publishing","\u002Finterface\u002Fsocial","1.interface\u002F13.social\u002F1.index",[150,152],{"title":146,"path":147,"stem":148,"icon":151},"sporty-newspaper",{"title":153,"path":154,"stem":155,"icon":22},"Connecting channels","\u002Finterface\u002Fsocial\u002Fchannels","1.interface\u002F13.social\u002F2.channels",false,{"title":158,"path":159,"stem":160,"children":161,"icon":164},"Website","\u002Fwebsite","2.website\u002F1.index",[162,165,170,174,179],{"title":163,"path":159,"stem":160,"icon":164},"Website builder","sporty-browser",{"title":166,"path":167,"stem":168,"icon":169},"Pages, hero and footer","\u002Fwebsite\u002Fpages","2.website\u002F2.pages","sporty-file-lines",{"title":171,"path":172,"stem":173,"icon":151},"News and events","\u002Fwebsite\u002Fnews-and-events","2.website\u002F3.news-and-events",{"title":175,"path":176,"stem":177,"icon":178},"Coaches and gallery","\u002Fwebsite\u002Fcoaches-and-gallery","2.website\u002F4.coaches-and-gallery","sporty-images",{"title":180,"path":181,"stem":182,"icon":183},"FAQ and sponsors","\u002Fwebsite\u002Ffaq-and-sponsors","2.website\u002F5.faq-and-sponsors","sporty-circle-question",{"title":185,"path":186,"stem":187,"children":188,"icon":190},"OAuth & Sign in with Sporty","\u002Foauth","4.oauth\u002F1.index",[189,191,195,199,203,207,211,215,219],{"title":185,"path":186,"stem":187,"icon":190},"sporty-brackets-curly",{"title":192,"path":193,"stem":194,"icon":190},"Registering an application","\u002Foauth\u002Fclients","4.oauth\u002F2.clients",{"title":196,"path":197,"stem":198,"icon":190},"The authorization code flow","\u002Foauth\u002Fauthorization-code","4.oauth\u002F3.authorization-code",{"title":200,"path":201,"stem":202,"icon":190},"Scopes","\u002Foauth\u002Fscopes","4.oauth\u002F4.scopes",{"title":204,"path":205,"stem":206,"icon":190},"Sign in with Sporty","\u002Foauth\u002Fsign-in-with-sporty","4.oauth\u002F5.sign-in-with-sporty",{"title":208,"path":209,"stem":210,"icon":190},"The partner API","\u002Foauth\u002Fpartner-api","4.oauth\u002F6.partner-api",{"title":212,"path":213,"stem":214,"icon":190},"Syncing bookings","\u002Foauth\u002Fbooking-sync","4.oauth\u002F7.booking-sync",{"title":216,"path":217,"stem":218,"icon":190},"MCP and AI clients","\u002Foauth\u002Fmcp-and-ai-clients","4.oauth\u002F8.mcp-and-ai-clients",{"title":220,"path":221,"stem":222,"icon":223},"Agent checkout","\u002Foauth\u002Fagent-checkout","4.oauth\u002F9.agent-checkout","sporty-cart-shopping",{"id":225,"title":204,"body":226,"description":812,"extension":813,"links":814,"meta":815,"navigation":816,"path":205,"seo":817,"stem":206,"__hash__":820},"docs\u002F4.oauth\u002F5.sign-in-with-sporty.md",{"type":227,"value":228,"toc":806},"minimark",[229,243,250,255,261,585,691,695,713,729,735,739,742,774,779,783,786,799,802],[230,231,232,233,237,238,242],"p",{},"If all you need is to know who someone is, you need OpenID Connect, which is\n",[234,235,236],"a",{"href":197},"the authorization code flow"," with ",[239,240,241],"code",{},"openid"," in the scope.",[230,244,245,246,249],{},"Point any OIDC library at ",[239,247,248],{},"https:\u002F\u002Fapi.sporty.plus\u002F.well-known\u002Fopenid-configuration"," and it\nwill configure itself. Writing the verification by hand is possible but rarely worth it.",[251,252,254],"h2",{"id":253},"the-id_token","The id_token",[230,256,257,258,260],{},"Returned alongside the access token when ",[239,259,241],{}," was granted. An RS256 JWT:",[262,263,268],"pre",{"className":264,"code":265,"language":266,"meta":267,"style":267},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"iss\": \"https:\u002F\u002Fapi.sporty.plus\",\n  \"sub\": \"9f1c2e40-...\",\n  \"aud\": \"your-client-id\",\n  \"iat\": 1789304059,\n  \"nbf\": 1789304059,\n  \"exp\": 1789307659,\n  \"auth_time\": 1789304050,\n  \"nonce\": \"what-you-sent\",\n  \"at_hash\": \"xQ7f...\",\n  \"name\": \"Ada Lovelace\",\n  \"given_name\": \"Ada\",\n  \"family_name\": \"Lovelace\",\n  \"locale\": \"hr\",\n  \"email\": \"ada@example.com\",\n  \"email_verified\": true\n}\n","json","",[239,269,270,279,307,328,349,367,383,400,417,438,459,480,501,522,543,564,579],{"__ignoreMap":267},[271,272,275],"span",{"class":273,"line":274},"line",1,[271,276,278],{"class":277},"sMK4o","{\n",[271,280,282,285,289,292,295,298,302,304],{"class":273,"line":281},2,[271,283,284],{"class":277},"  \"",[271,286,288],{"class":287},"spNyl","iss",[271,290,291],{"class":277},"\"",[271,293,294],{"class":277},":",[271,296,297],{"class":277}," \"",[271,299,301],{"class":300},"sfazB","https:\u002F\u002Fapi.sporty.plus",[271,303,291],{"class":277},[271,305,306],{"class":277},",\n",[271,308,310,312,315,317,319,321,324,326],{"class":273,"line":309},3,[271,311,284],{"class":277},[271,313,314],{"class":287},"sub",[271,316,291],{"class":277},[271,318,294],{"class":277},[271,320,297],{"class":277},[271,322,323],{"class":300},"9f1c2e40-...",[271,325,291],{"class":277},[271,327,306],{"class":277},[271,329,331,333,336,338,340,342,345,347],{"class":273,"line":330},4,[271,332,284],{"class":277},[271,334,335],{"class":287},"aud",[271,337,291],{"class":277},[271,339,294],{"class":277},[271,341,297],{"class":277},[271,343,344],{"class":300},"your-client-id",[271,346,291],{"class":277},[271,348,306],{"class":277},[271,350,352,354,357,359,361,365],{"class":273,"line":351},5,[271,353,284],{"class":277},[271,355,356],{"class":287},"iat",[271,358,291],{"class":277},[271,360,294],{"class":277},[271,362,364],{"class":363},"sbssI"," 1789304059",[271,366,306],{"class":277},[271,368,370,372,375,377,379,381],{"class":273,"line":369},6,[271,371,284],{"class":277},[271,373,374],{"class":287},"nbf",[271,376,291],{"class":277},[271,378,294],{"class":277},[271,380,364],{"class":363},[271,382,306],{"class":277},[271,384,386,388,391,393,395,398],{"class":273,"line":385},7,[271,387,284],{"class":277},[271,389,390],{"class":287},"exp",[271,392,291],{"class":277},[271,394,294],{"class":277},[271,396,397],{"class":363}," 1789307659",[271,399,306],{"class":277},[271,401,403,405,408,410,412,415],{"class":273,"line":402},8,[271,404,284],{"class":277},[271,406,407],{"class":287},"auth_time",[271,409,291],{"class":277},[271,411,294],{"class":277},[271,413,414],{"class":363}," 1789304050",[271,416,306],{"class":277},[271,418,420,422,425,427,429,431,434,436],{"class":273,"line":419},9,[271,421,284],{"class":277},[271,423,424],{"class":287},"nonce",[271,426,291],{"class":277},[271,428,294],{"class":277},[271,430,297],{"class":277},[271,432,433],{"class":300},"what-you-sent",[271,435,291],{"class":277},[271,437,306],{"class":277},[271,439,441,443,446,448,450,452,455,457],{"class":273,"line":440},10,[271,442,284],{"class":277},[271,444,445],{"class":287},"at_hash",[271,447,291],{"class":277},[271,449,294],{"class":277},[271,451,297],{"class":277},[271,453,454],{"class":300},"xQ7f...",[271,456,291],{"class":277},[271,458,306],{"class":277},[271,460,462,464,467,469,471,473,476,478],{"class":273,"line":461},11,[271,463,284],{"class":277},[271,465,466],{"class":287},"name",[271,468,291],{"class":277},[271,470,294],{"class":277},[271,472,297],{"class":277},[271,474,475],{"class":300},"Ada Lovelace",[271,477,291],{"class":277},[271,479,306],{"class":277},[271,481,483,485,488,490,492,494,497,499],{"class":273,"line":482},12,[271,484,284],{"class":277},[271,486,487],{"class":287},"given_name",[271,489,291],{"class":277},[271,491,294],{"class":277},[271,493,297],{"class":277},[271,495,496],{"class":300},"Ada",[271,498,291],{"class":277},[271,500,306],{"class":277},[271,502,504,506,509,511,513,515,518,520],{"class":273,"line":503},13,[271,505,284],{"class":277},[271,507,508],{"class":287},"family_name",[271,510,291],{"class":277},[271,512,294],{"class":277},[271,514,297],{"class":277},[271,516,517],{"class":300},"Lovelace",[271,519,291],{"class":277},[271,521,306],{"class":277},[271,523,525,527,530,532,534,536,539,541],{"class":273,"line":524},14,[271,526,284],{"class":277},[271,528,529],{"class":287},"locale",[271,531,291],{"class":277},[271,533,294],{"class":277},[271,535,297],{"class":277},[271,537,538],{"class":300},"hr",[271,540,291],{"class":277},[271,542,306],{"class":277},[271,544,546,548,551,553,555,557,560,562],{"class":273,"line":545},15,[271,547,284],{"class":277},[271,549,550],{"class":287},"email",[271,552,291],{"class":277},[271,554,294],{"class":277},[271,556,297],{"class":277},[271,558,559],{"class":300},"ada@example.com",[271,561,291],{"class":277},[271,563,306],{"class":277},[271,565,567,569,572,574,576],{"class":273,"line":566},16,[271,568,284],{"class":277},[271,570,571],{"class":287},"email_verified",[271,573,291],{"class":277},[271,575,294],{"class":277},[271,577,578],{"class":277}," true\n",[271,580,582],{"class":273,"line":581},17,[271,583,584],{"class":277},"}\n",[586,587,588,601],"table",{},[589,590,591],"thead",{},[592,593,594,598],"tr",{},[595,596,597],"th",{},"Claim",[595,599,600],{},"Notes",[602,603,604,619,628,637,646,659,679],"tbody",{},[592,605,606,611],{},[607,608,609],"td",{},[239,610,314],{},[607,612,613,614,618],{},"The member's permanent id. ",[615,616,617],"strong",{},"This is the one to store."," It never changes; an email address can.",[592,620,621,625],{},[607,622,623],{},[239,624,335],{},[607,626,627],{},"Your client id. Check it.",[592,629,630,634],{},[607,631,632],{},[239,633,424],{},[607,635,636],{},"Present if you sent one. Check it.",[592,638,639,643],{},[607,640,641],{},[239,642,445],{},[607,644,645],{},"Binds this id_token to the access token issued with it.",[592,647,648,652],{},[607,649,650],{},[239,651,407],{},[607,653,654,655,658],{},"When the member approved. Not necessarily when they signed in — we do not record that, so do not build ",[239,656,657],{},"max_age"," behaviour on it.",[592,660,661,672],{},[607,662,663,665,666,665,668,665,670],{},[239,664,466],{},", ",[239,667,487],{},[239,669,508],{},[239,671,529],{},[607,673,674,675,678],{},"Only with ",[239,676,677],{},"profile",".",[592,680,681,687],{},[607,682,683,665,685],{},[239,684,550],{},[239,686,571],{},[607,688,674,689,678],{},[239,690,550],{},[251,692,694],{"id":693},"verifying-it","Verifying it",[230,696,697,698,701,702,705,706,665,708,710,711,678],{},"Fetch ",[239,699,700],{},"https:\u002F\u002Fapi.sporty.plus\u002Foauth2\u002Fjwks",", pick the key whose ",[239,703,704],{},"kid"," matches the token\nheader, verify RS256, then check ",[239,707,288],{},[239,709,335],{}," and ",[239,712,390],{},[262,714,718],{"className":715,"code":716,"language":717,"meta":267,"style":267},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","curl https:\u002F\u002Fapi.sporty.plus\u002Foauth2\u002Fjwks\n","bash",[239,719,720],{"__ignoreMap":267},[271,721,722,726],{"class":273,"line":274},[271,723,725],{"class":724},"sBMFI","curl",[271,727,728],{"class":300}," https:\u002F\u002Fapi.sporty.plus\u002Foauth2\u002Fjwks\n",[230,730,731,732,734],{},"Cache the JWKS — an hour is sensible — but re-fetch when you meet a ",[239,733,704],{}," you do not know,\nrather than failing.",[251,736,738],{"id":737},"userinfo","\u002Fuserinfo",[230,740,741],{},"An id_token is a snapshot. For current values:",[262,743,745],{"className":715,"code":744,"language":717,"meta":267,"style":267},"curl https:\u002F\u002Fapi.sporty.plus\u002Foauth2\u002Fuserinfo \\\n  -H \"Authorization: Bearer $ACCESS_TOKEN\"\n",[239,746,747,758],{"__ignoreMap":267},[271,748,749,751,754],{"class":273,"line":274},[271,750,725],{"class":724},[271,752,753],{"class":300}," https:\u002F\u002Fapi.sporty.plus\u002Foauth2\u002Fuserinfo",[271,755,757],{"class":756},"sTEyZ"," \\\n",[271,759,760,763,765,768,771],{"class":273,"line":281},[271,761,762],{"class":300},"  -H",[271,764,297],{"class":277},[271,766,767],{"class":300},"Authorization: Bearer ",[271,769,770],{"class":756},"$ACCESS_TOKEN",[271,772,773],{"class":277},"\"\n",[230,775,776,777,678],{},"The same claims, gated the same way by scope, always including ",[239,778,314],{},[251,780,782],{"id":781},"key-rotation","Key rotation",[230,784,785],{},"We rotate the signing key rarely, and when we do:",[787,788,789,793],"ul",{},[790,791,792],"li",{},"the new public key appears in the JWKS, alongside the old one, before anything is signed\nwith it;",[790,794,795,798],{},[615,796,797],{},"every existing access token stops working."," The signing key is shared with access\ntokens, so a rotation ends them. Your refresh tokens survive — use them, and be ready to\nre-authorise if that fails.",[230,800,801],{},"If you ever see a valid-looking token suddenly rejected, refresh once before assuming\nanything is broken.",[803,804,805],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}",{"title":267,"searchDepth":281,"depth":281,"links":807},[808,809,810,811],{"id":253,"depth":281,"text":254},{"id":693,"depth":281,"text":694},{"id":737,"depth":281,"text":738},{"id":781,"depth":281,"text":782},"OpenID Connect — the id_token, its claims, \u002Fuserinfo and verifying a signature.","md",null,{},{"icon":190},{"title":818,"description":819},"Sign in with Sporty — OpenID Connect","id_token claims, the userinfo endpoint, JWKS and key rotation.","wUDOnJC-sovs5zTWwdwila8CNEmehfA38ZRIJfjDWOs",[822,824],{"title":200,"path":201,"stem":202,"description":823,"icon":190,"children":-1},"Every scope, what the member is told it means, and which kinds of client may ask for it.",{"title":208,"path":209,"stem":210,"description":825,"icon":190,"children":-1},"What an access token can actually read and write, and what it deliberately cannot.",1790691909306]