[{"data":1,"prerenderedAt":550},["ShallowReactive",2],{"navigation_docs":3,"-oauth":224,"-oauth-surround":545},[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":185,"body":226,"description":536,"extension":537,"links":538,"meta":539,"navigation":540,"path":186,"seo":541,"stem":187,"__hash__":544},"docs\u002F4.oauth\u002F1.index.md",{"type":227,"value":228,"toc":530},"minimark",[229,233,236,241,323,326,330,337,423,426,464,468,478,489,493,526],[230,231,232],"p",{},"Sporty is an OAuth 2.1 and OpenID Connect provider. Your application can ask a member for\npermission, receive a scoped access token, and use it to read the things they agreed to —\nwithout ever seeing their password, and with the member able to take that access back at any\ntime.",[230,234,235],{},"Everything here is standard. Any OAuth or OIDC client library will work; you should not need\nto write anything Sporty-specific.",[237,238,240],"h2",{"id":239},"which-flow-you-want","Which flow you want",[242,243,244,257],"table",{},[245,246,247],"thead",{},[248,249,250,254],"tr",{},[251,252,253],"th",{},"You are building",[251,255,256],{},"Use",[258,259,260,272,287,297,310],"tbody",{},[248,261,262,266],{},[263,264,265],"td",{},"A web, mobile or desktop app that acts for the person using it",[263,267,268],{},[269,270,271],"strong",{},"Authorization code + PKCE",[248,273,274,277],{},[263,275,276],{},"\"Sign in with Sporty\" — you just need to know who someone is",[263,278,279,281,282,286],{},[269,280,271],{},", with the ",[283,284,285],"code",{},"openid"," scope",[248,288,289,292],{},[263,290,291],{},"A server-to-server integration acting for a club, with no person present",[263,293,294],{},[269,295,296],{},"Client credentials",[248,298,299,302],{},[263,300,301],{},"A booking system keeping its diary in step with a club's",[263,303,304,306,307],{},[269,305,296],{},", see ",[308,309,212],"a",{"href":213},[248,311,312,315],{},[263,313,314],{},"An AI agent or MCP client",[263,316,317,319,320],{},[269,318,271],{},", usually with ",[308,321,322],{"href":217},"dynamic registration",[230,324,325],{},"There is no password grant and no implicit grant. OAuth 2.1 removes both.",[237,327,329],{"id":328},"endpoints","Endpoints",[230,331,332,333,336],{},"Everything lives on ",[283,334,335],{},"https:\u002F\u002Fapi.sporty.plus",".",[242,338,339,349],{},[245,340,341],{},[248,342,343,346],{},[251,344,345],{},"Purpose",[251,347,348],{},"Endpoint",[258,350,351,361,371,388,403,413],{},[248,352,353,356],{},[263,354,355],{},"Authorization",[263,357,358],{},[283,359,360],{},"GET \u002Foauth2\u002Fauthorize",[248,362,363,366],{},[263,364,365],{},"Token",[263,367,368],{},[283,369,370],{},"POST \u002Foauth2\u002Ftoken",[248,372,373,383],{},[263,374,375,376,382],{},"Revocation (",[308,377,381],{"href":378,"rel":379},"https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc7009",[380],"nofollow","RFC 7009",")",[263,384,385],{},[283,386,387],{},"POST \u002Foauth2\u002Ftoken\u002Frevoke",[248,389,390,398],{},[263,391,392,393,382],{},"Dynamic registration (",[308,394,397],{"href":395,"rel":396},"https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc7591",[380],"RFC 7591",[263,399,400],{},[283,401,402],{},"POST \u002Foauth2\u002Fregister",[248,404,405,408],{},[263,406,407],{},"UserInfo",[263,409,410],{},[283,411,412],{},"GET \u002Foauth2\u002Fuserinfo",[248,414,415,418],{},[263,416,417],{},"JWKS",[263,419,420],{},[283,421,422],{},"GET \u002Foauth2\u002Fjwks",[230,424,425],{},"Rather than hard-coding those, fetch one of the discovery documents:",[427,428,433],"pre",{"className":429,"code":430,"language":431,"meta":432,"style":432},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","curl https:\u002F\u002Fapi.sporty.plus\u002F.well-known\u002Fopenid-configuration\ncurl https:\u002F\u002Fapi.sporty.plus\u002F.well-known\u002Foauth-authorization-server\ncurl https:\u002F\u002Fapi.sporty.plus\u002F.well-known\u002Foauth-protected-resource\n","bash","",[283,434,435,448,456],{"__ignoreMap":432},[436,437,440,444],"span",{"class":438,"line":439},"line",1,[436,441,443],{"class":442},"sBMFI","curl",[436,445,447],{"class":446},"sfazB"," https:\u002F\u002Fapi.sporty.plus\u002F.well-known\u002Fopenid-configuration\n",[436,449,451,453],{"class":438,"line":450},2,[436,452,443],{"class":442},[436,454,455],{"class":446}," https:\u002F\u002Fapi.sporty.plus\u002F.well-known\u002Foauth-authorization-server\n",[436,457,459,461],{"class":438,"line":458},3,[436,460,443],{"class":442},[436,462,463],{"class":446}," https:\u002F\u002Fapi.sporty.plus\u002F.well-known\u002Foauth-protected-resource\n",[237,465,467],{"id":466},"where-tokens-work","Where tokens work",[230,469,470,471,474,475,336],{},"An access token is spent on the ",[269,472,473],{},"partner API",", ",[283,476,477],{},"https:\u002F\u002Fapi.sporty.plus\u002Fapi\u002Fpartner\u002Fv1",[230,479,480,481,484,485,488],{},"It will not work anywhere else. In particular ",[283,482,483],{},"\u002Fapi\u002Fv3",", the API our own apps use, refuses\nOAuth tokens outright and answers ",[283,486,487],{},"403"," with a message saying so. That surface is authorised\nfor people using our own interface, not for applications acting on their behalf, and letting\na token in there would grant far more than any consent screen described.",[237,490,492],{"id":491},"next","Next",[494,495,496,501,506,510,514,518,522],"ul",{},[497,498,499],"li",{},[308,500,192],{"href":193},[497,502,503],{},[308,504,505],{"href":197},"The authorization code flow, step by step",[497,507,508],{},[308,509,200],{"href":201},[497,511,512],{},[308,513,204],{"href":205},[497,515,516],{},[308,517,208],{"href":209},[497,519,520],{},[308,521,212],{"href":213},[497,523,524],{},[308,525,216],{"href":217},[527,528,529],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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);}",{"title":432,"searchDepth":450,"depth":450,"links":531},[532,533,534,535],{"id":239,"depth":450,"text":240},{"id":328,"depth":450,"text":329},{"id":466,"depth":450,"text":467},{"id":491,"depth":450,"text":492},"Let people connect your application to their Sporty account, with their permission and nothing more.","md",null,{},{"icon":190},{"title":542,"description":543},"Sporty OAuth 2.1 and OpenID Connect","Authorization code with PKCE, refresh tokens, client credentials, and OpenID Connect on api.sporty.plus.","JV2gq3-Ku9ZaFIYDIxp3Gg82aVOTclgni5QXvLTAUeg",[546,548],{"title":180,"path":181,"stem":182,"description":547,"icon":183,"children":-1},"Here we learn how to manage frequently asked questions and sponsor logos",{"title":192,"path":193,"stem":194,"description":549,"icon":190,"children":-1},"How to get a client id, what a redirect URI may look like, and what \"pending review\" means.",1790691909306]