[{"data":1,"prerenderedAt":1127},["ShallowReactive",2],{"navigation_docs_en":3,"-en-oauth-authorization-code":312,"-en-oauth-authorization-code-surround":1122},[4,17,210,237,272],{"title":5,"path":6,"stem":7,"children":8,"icon":11},"Getting started","\u002Fen\u002Fgetting-started","en\u002F0.getting-started\u002F1.index",[9,12],{"title":10,"path":6,"stem":7,"icon":11},"Tour of the admin","sporty-toggle-large-on",{"title":13,"path":14,"stem":15,"icon":16},"First-week setup","\u002Fen\u002Fgetting-started\u002Ffirst-week-setup","en\u002F0.getting-started\u002F2.first-week-setup","sporty-calendar-check",{"title":18,"path":19,"stem":20,"children":21,"page":209},"Interface","\u002Fen\u002Finterface","en\u002F1.interface",[22,65,72,79,90,97,105,112,119,126,147,154,174,185,203],{"title":23,"path":24,"stem":25,"children":26,"icon":28},"Courts","\u002Fen\u002Finterface\u002Fcourts","en\u002F1.interface\u002F01.courts\u002F1.index",[27,29],{"title":23,"path":24,"stem":25,"icon":28},"sporty-court-sport",{"title":30,"path":31,"stem":32,"children":33,"icon":11},"Access control and lights","\u002Fen\u002Finterface\u002Fcourts\u002Fintegrations","en\u002F1.interface\u002F01.courts\u002F5.integrations\u002F1.index",[34,35,40,45],{"title":30,"path":31,"stem":32,"icon":11},{"title":36,"path":37,"stem":38,"icon":39},"Weblock","\u002Fen\u002Finterface\u002Fcourts\u002Fintegrations\u002Fweblock","en\u002F1.interface\u002F01.courts\u002F5.integrations\u002F2.weblock","sporty-door-open",{"title":41,"path":42,"stem":43,"icon":44},"Shelly","\u002Fen\u002Finterface\u002Fcourts\u002Fintegrations\u002Fshelly","en\u002F1.interface\u002F01.courts\u002F5.integrations\u002F3.shelly","sporty-bolt",{"title":46,"path":47,"stem":48,"children":49,"icon":39},"UniFi Access","\u002Fen\u002Finterface\u002Fcourts\u002Fintegrations\u002Funifi-access","en\u002F1.interface\u002F01.courts\u002F5.integrations\u002F4.unifi-access\u002F1.index",[50,52,56,61],{"title":51,"path":47,"stem":48,"icon":39},"Overview",{"title":53,"path":54,"stem":55,"icon":11},"Connect the VPN","\u002Fen\u002Finterface\u002Fcourts\u002Fintegrations\u002Funifi-access\u002Fvpn","en\u002F1.interface\u002F01.courts\u002F5.integrations\u002F4.unifi-access\u002F2.vpn",{"title":57,"path":58,"stem":59,"icon":60},"Create an API token","\u002Fen\u002Finterface\u002Fcourts\u002Fintegrations\u002Funifi-access\u002Fapi-token","en\u002F1.interface\u002F01.courts\u002F5.integrations\u002F4.unifi-access\u002F3.api-token","sporty-gear",{"title":62,"path":63,"stem":64,"icon":28},"Set it up in Club Admin","\u002Fen\u002Finterface\u002Fcourts\u002Fintegrations\u002Funifi-access\u002Fclub-admin","en\u002F1.interface\u002F01.courts\u002F5.integrations\u002F4.unifi-access\u002F4.club-admin",{"title":66,"path":67,"stem":68,"children":69,"icon":71},"Members","\u002Fen\u002Finterface\u002Fmembers","en\u002F1.interface\u002F02.members\u002F1.index",[70],{"title":66,"path":67,"stem":68,"icon":71},"sporty-user-group",{"title":73,"path":74,"stem":75,"children":76,"icon":78},"Memberships","\u002Fen\u002Finterface\u002Fmemberships","en\u002F1.interface\u002F03.memberships\u002F1.index",[77],{"title":73,"path":74,"stem":75,"icon":78},"sporty-id-card",{"title":80,"path":81,"stem":82,"children":83,"icon":85},"Leagues","\u002Fen\u002Finterface\u002Fleagues","en\u002F1.interface\u002F04.leagues\u002F1.index",[84,86],{"title":80,"path":81,"stem":82,"icon":85},"sporty-ranking-star",{"title":87,"path":88,"stem":89,"icon":16},"Planned competitions","\u002Fen\u002Finterface\u002Fleagues\u002Fplanned-competitions","en\u002F1.interface\u002F04.leagues\u002F2.planned-competitions",{"title":91,"path":92,"stem":93,"children":94,"icon":96},"Tournaments","\u002Fen\u002Finterface\u002Ftournaments","en\u002F1.interface\u002F05.tournaments\u002F1.index",[95],{"title":91,"path":92,"stem":93,"icon":96},"sporty-trophy",{"title":98,"path":99,"stem":100,"children":101,"icon":104},"Payments and subscriptions","\u002Fen\u002Finterface\u002Fpayments","en\u002F1.interface\u002F06.payments\u002F1.index",[102],{"title":103,"path":99,"stem":100,"icon":104},"Payments","sporty-credit-card",{"title":106,"path":107,"stem":108,"children":109,"icon":111},"Shop","\u002Fen\u002Finterface\u002Fshop","en\u002F1.interface\u002F07.shop\u002F1.index",[110],{"title":106,"path":107,"stem":108,"icon":111},"sporty-bag-shopping",{"title":113,"path":114,"stem":115,"children":116,"icon":118},"Schools and coaches","\u002Fen\u002Finterface\u002Fschools","en\u002F1.interface\u002F08.schools\u002F1.index",[117],{"title":113,"path":114,"stem":115,"icon":118},"sporty-graduation-cap",{"title":120,"path":121,"stem":122,"children":123,"icon":125},"Emails","\u002Fen\u002Finterface\u002Femails","en\u002F1.interface\u002F09.emails\u002F1.index",[124],{"title":120,"path":121,"stem":122,"icon":125},"sporty-envelope",{"title":127,"path":128,"stem":129,"children":130,"icon":132},"Video and cameras","\u002Fen\u002Finterface\u002Fvideo","en\u002F1.interface\u002F10.video\u002F1.index",[131,133,137,142],{"title":127,"path":128,"stem":129,"icon":132},"sporty-camera-cctv",{"title":134,"path":135,"stem":136,"icon":132},"Dahua cameras","\u002Fen\u002Finterface\u002Fvideo\u002Fdahua","en\u002F1.interface\u002F10.video\u002F2.dahua",{"title":138,"path":139,"stem":140,"icon":141},"Other RTMP cameras","\u002Fen\u002Finterface\u002Fvideo\u002Frtmp","en\u002F1.interface\u002F10.video\u002F3.rtmp","sporty-video",{"title":143,"path":144,"stem":145,"icon":146},"Match analytics","\u002Fen\u002Finterface\u002Fvideo\u002Fanalytics","en\u002F1.interface\u002F10.video\u002F4.analytics","sporty-chart-simple",{"title":148,"path":149,"stem":150,"children":151,"icon":153},"Reports","\u002Fen\u002Finterface\u002Freports","en\u002F1.interface\u002F11.reports\u002F1.index",[152],{"title":148,"path":149,"stem":150,"icon":153},"sporty-chart-mixed",{"title":155,"path":156,"stem":157,"children":158,"icon":60},"Settings","\u002Fen\u002Finterface\u002Fsettings","en\u002F1.interface\u002F12.settings\u002F1.index",[159,161,165,169],{"title":160,"path":156,"stem":157,"icon":60},"Club settings",{"title":162,"path":163,"stem":164,"icon":16},"Booking rules and price list","\u002Fen\u002Finterface\u002Fsettings\u002Fbooking-rules","en\u002F1.interface\u002F12.settings\u002F2.booking-rules",{"title":166,"path":167,"stem":168,"icon":78},"Sign-up and legal pages","\u002Fen\u002Finterface\u002Fsettings\u002Fsignup-and-legal","en\u002F1.interface\u002F12.settings\u002F3.signup-and-legal",{"title":170,"path":171,"stem":172,"icon":173},"Administrators and roles","\u002Fen\u002Finterface\u002Fsettings\u002Fadministrators-and-roles","en\u002F1.interface\u002F12.settings\u002F4.administrators-and-roles","sporty-user",{"title":175,"path":176,"stem":177,"children":178,"icon":180},"Social publishing","\u002Fen\u002Finterface\u002Fsocial","en\u002F1.interface\u002F13.social\u002F1.index",[179,181],{"title":175,"path":176,"stem":177,"icon":180},"sporty-newspaper",{"title":182,"path":183,"stem":184,"icon":11},"Connecting channels","\u002Fen\u002Finterface\u002Fsocial\u002Fchannels","en\u002F1.interface\u002F13.social\u002F2.channels",{"title":186,"path":187,"stem":188,"children":189,"icon":28},"Seated events","\u002Fen\u002Finterface\u002Fseated-events","en\u002F1.interface\u002F14.seated-events\u002F1.index",[190,191,195,199],{"title":186,"path":187,"stem":188,"icon":28},{"title":192,"path":193,"stem":194,"icon":28},"Seating plans","\u002Fen\u002Finterface\u002Fseated-events\u002Fseating-plans","en\u002F1.interface\u002F14.seated-events\u002F2.seating-plans",{"title":196,"path":197,"stem":198,"icon":16},"Selling seats","\u002Fen\u002Finterface\u002Fseated-events\u002Fselling-seats","en\u002F1.interface\u002F14.seated-events\u002F3.selling-seats",{"title":200,"path":201,"stem":202,"icon":39},"On sale and at the door","\u002Fen\u002Finterface\u002Fseated-events\u002Fon-sale","en\u002F1.interface\u002F14.seated-events\u002F4.on-sale",{"title":204,"path":205,"stem":206,"children":207,"icon":16},"Season tickets","\u002Fen\u002Finterface\u002Fseason-tickets","en\u002F1.interface\u002F15.season-tickets\u002F1.index",[208],{"title":204,"path":205,"stem":206,"icon":16},false,{"title":211,"path":212,"stem":213,"children":214,"icon":217},"Website","\u002Fen\u002Fwebsite","en\u002F2.website\u002F1.index",[215,218,223,227,232],{"title":216,"path":212,"stem":213,"icon":217},"Website builder","sporty-browser",{"title":219,"path":220,"stem":221,"icon":222},"Pages, hero and footer","\u002Fen\u002Fwebsite\u002Fpages","en\u002F2.website\u002F2.pages","sporty-file-lines",{"title":224,"path":225,"stem":226,"icon":180},"News and events","\u002Fen\u002Fwebsite\u002Fnews-and-events","en\u002F2.website\u002F3.news-and-events",{"title":228,"path":229,"stem":230,"icon":231},"Coaches and gallery","\u002Fen\u002Fwebsite\u002Fcoaches-and-gallery","en\u002F2.website\u002F4.coaches-and-gallery","sporty-images",{"title":233,"path":234,"stem":235,"icon":236},"FAQ and sponsors","\u002Fen\u002Fwebsite\u002Ffaq-and-sponsors","en\u002F2.website\u002F5.faq-and-sponsors","sporty-circle-question",{"title":238,"path":239,"stem":240,"children":241,"icon":173},"For members","\u002Fen\u002Fmembers","en\u002F3.members\u002F1.index",[242,244,248,252,256,260,264,268],{"title":243,"path":239,"stem":240,"icon":173},"Using the member app",{"title":245,"path":246,"stem":247,"icon":16},"Booking a court","\u002Fen\u002Fmembers\u002Fbooking","en\u002F3.members\u002F2.booking",{"title":249,"path":250,"stem":251,"icon":104},"Memberships and payments","\u002Fen\u002Fmembers\u002Fpayments","en\u002F3.members\u002F3.payments",{"title":253,"path":254,"stem":255,"icon":85},"How competitions work","\u002Fen\u002Fmembers\u002Fhow-competitions-work","en\u002F3.members\u002F4.how-competitions-work",{"title":257,"path":258,"stem":259,"icon":96},"Leagues, tournaments and results","\u002Fen\u002Fmembers\u002Fcompetitions","en\u002F3.members\u002F5.competitions",{"title":261,"path":262,"stem":263,"icon":71},"Family and children","\u002Fen\u002Fmembers\u002Ffamily","en\u002F3.members\u002F6.family",{"title":265,"path":266,"stem":267,"icon":78},"Your account","\u002Fen\u002Fmembers\u002Faccount","en\u002F3.members\u002F7.account",{"title":269,"path":270,"stem":271,"icon":236},"Getting help","\u002Fen\u002Fmembers\u002Fhelp","en\u002F3.members\u002F8.help",{"title":273,"path":274,"stem":275,"children":276,"icon":278},"OAuth & Sign in with Sporty","\u002Fen\u002Foauth","en\u002F4.oauth\u002F1.index",[277,279,283,287,291,295,299,303,307],{"title":273,"path":274,"stem":275,"icon":278},"sporty-brackets-curly",{"title":280,"path":281,"stem":282,"icon":278},"Registering an application","\u002Fen\u002Foauth\u002Fclients","en\u002F4.oauth\u002F2.clients",{"title":284,"path":285,"stem":286,"icon":278},"The authorization code flow","\u002Fen\u002Foauth\u002Fauthorization-code","en\u002F4.oauth\u002F3.authorization-code",{"title":288,"path":289,"stem":290,"icon":278},"Scopes","\u002Fen\u002Foauth\u002Fscopes","en\u002F4.oauth\u002F4.scopes",{"title":292,"path":293,"stem":294,"icon":278},"Sign in with Sporty","\u002Fen\u002Foauth\u002Fsign-in-with-sporty","en\u002F4.oauth\u002F5.sign-in-with-sporty",{"title":296,"path":297,"stem":298,"icon":278},"The partner API","\u002Fen\u002Foauth\u002Fpartner-api","en\u002F4.oauth\u002F6.partner-api",{"title":300,"path":301,"stem":302,"icon":278},"Syncing bookings","\u002Fen\u002Foauth\u002Fbooking-sync","en\u002F4.oauth\u002F7.booking-sync",{"title":304,"path":305,"stem":306,"icon":278},"MCP and AI clients","\u002Fen\u002Foauth\u002Fmcp-and-ai-clients","en\u002F4.oauth\u002F8.mcp-and-ai-clients",{"title":308,"path":309,"stem":310,"icon":311},"Agent checkout","\u002Fen\u002Foauth\u002Fagent-checkout","en\u002F4.oauth\u002F9.agent-checkout","sporty-cart-shopping",{"id":313,"title":284,"body":314,"description":1113,"extension":1114,"links":1115,"meta":1116,"navigation":1117,"path":285,"seo":1118,"stem":286,"__hash__":1121},"docs_en\u002Fen\u002F4.oauth\u002F3.authorization-code.md",{"type":315,"value":316,"toc":1103},"minimark",[317,321,326,343,491,494,498,506,560,567,571,577,580,586,592,596,599,700,707,821,834,838,866,870,873,934,938,979,993,1001,1008,1012,1092,1099],[318,319,320],"p",{},"Authorization code with PKCE, which is the flow for any application acting on behalf of a\nperson. Every example below is a real request.",[322,323,325],"h2",{"id":324},"_1-make-a-pkce-verifier-and-challenge","1. Make a PKCE verifier and challenge",[318,327,328,329,333,334,338,339,342],{},"PKCE is ",[330,331,332],"strong",{},"required",", for confidential clients too, and only ",[335,336,337],"code",{},"S256"," is accepted — ",[335,340,341],{},"plain"," is\nrefused.",[344,345,350],"pre",{"className":346,"code":347,"language":348,"meta":349,"style":349},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","VERIFIER=$(openssl rand -base64 60 | tr -d '\\n=+\u002F' | cut -c1-64)\nCHALLENGE=$(printf '%s' \"$VERIFIER\" | openssl dgst -sha256 -binary | openssl base64 | tr '+\u002F' '-_' | tr -d '=')\n","bash","",[335,351,352,409],{"__ignoreMap":349},[353,354,357,361,365,369,373,376,380,383,386,389,392,395,398,400,403,406],"span",{"class":355,"line":356},"line",1,[353,358,360],{"class":359},"sTEyZ","VERIFIER",[353,362,364],{"class":363},"sMK4o","=$(",[353,366,368],{"class":367},"sBMFI","openssl",[353,370,372],{"class":371},"sfazB"," rand",[353,374,375],{"class":371}," -base64",[353,377,379],{"class":378},"sbssI"," 60",[353,381,382],{"class":363}," |",[353,384,385],{"class":367}," tr",[353,387,388],{"class":371}," -d",[353,390,391],{"class":363}," '",[353,393,394],{"class":371},"\\n=+\u002F",[353,396,397],{"class":363},"'",[353,399,382],{"class":363},[353,401,402],{"class":367}," cut",[353,404,405],{"class":371}," -c1-64",[353,407,408],{"class":363},")\n",[353,410,412,415,417,421,423,426,428,431,434,437,439,442,445,448,451,453,455,458,460,462,464,467,469,471,474,476,478,480,482,484,487,489],{"class":355,"line":411},2,[353,413,414],{"class":359},"CHALLENGE",[353,416,364],{"class":363},[353,418,420],{"class":419},"s2Zo4","printf",[353,422,391],{"class":363},[353,424,425],{"class":371},"%s",[353,427,397],{"class":363},[353,429,430],{"class":363}," \"",[353,432,433],{"class":359},"$VERIFIER",[353,435,436],{"class":363},"\"",[353,438,382],{"class":363},[353,440,441],{"class":367}," openssl",[353,443,444],{"class":371}," dgst",[353,446,447],{"class":371}," -sha256",[353,449,450],{"class":371}," -binary",[353,452,382],{"class":363},[353,454,441],{"class":367},[353,456,457],{"class":371}," base64",[353,459,382],{"class":363},[353,461,385],{"class":367},[353,463,391],{"class":363},[353,465,466],{"class":371},"+\u002F",[353,468,397],{"class":363},[353,470,391],{"class":363},[353,472,473],{"class":371},"-_",[353,475,397],{"class":363},[353,477,382],{"class":363},[353,479,385],{"class":367},[353,481,388],{"class":371},[353,483,391],{"class":363},[353,485,486],{"class":371},"=",[353,488,397],{"class":363},[353,490,408],{"class":363},[318,492,493],{},"Keep the verifier; you need it in step 4.",[322,495,497],{"id":496},"_2-send-the-member-to-sporty","2. Send the member to Sporty",[344,499,504],{"className":500,"code":502,"language":503},[501],"language-text","https:\u002F\u002Fapi.sporty.plus\u002Foauth2\u002Fauthorize\n  ?response_type=code\n  &client_id=YOUR_CLIENT_ID\n  &redirect_uri=https:\u002F\u002Fyourapp.example\u002Fcallback\n  &scope=openid%20profile%20email%20club.courts.read\n  &state=RANDOM_PER_REQUEST\n  &code_challenge=CHALLENGE\n  &code_challenge_method=S256\n","text",[335,505,502],{"__ignoreMap":349},[507,508,509,522],"table",{},[510,511,512],"thead",{},[513,514,515,519],"tr",{},[516,517,518],"th",{},"Parameter",[516,520,521],{},"Notes",[523,524,525,536,550],"tbody",{},[513,526,527,533],{},[528,529,530],"td",{},[335,531,532],{},"state",[528,534,535],{},"Random, unguessable, per request. Check it on the way back — that is what makes the callback yours.",[513,537,538,543],{},[528,539,540],{},[335,541,542],{},"nonce",[528,544,545,546,549],{},"Optional. If you send it, it comes back in the ",[335,547,548],{},"id_token",". Use it if you want one.",[513,551,552,557],{},[528,553,554],{},[335,555,556],{},"club_id",[528,558,559],{},"Optional. Only meaningful for a client granted access to several clubs, to say which one this is about.",[318,561,562,563,566],{},"The member sees a consent screen on ",[335,564,565],{},"my.sporty.plus"," listing, in plain language, exactly what\nyou asked for. They can approve less than you asked for; grant requests are never widened.",[322,568,570],{"id":569},"_3-they-come-back-to-your-redirect-uri","3. They come back to your redirect URI",[344,572,575],{"className":573,"code":574,"language":503},[501],"https:\u002F\u002Fyourapp.example\u002Fcallback?code=...&state=...\n",[335,576,574],{"__ignoreMap":349},[318,578,579],{},"If they declined, or something was wrong:",[344,581,584],{"className":582,"code":583,"language":503},[501],"https:\u002F\u002Fyourapp.example\u002Fcallback?error=access_denied&error_description=...&state=...\n",[335,585,583],{"__ignoreMap":349},[318,587,588,589,591],{},"Compare ",[335,590,532],{}," with what you sent before doing anything else.",[322,593,595],{"id":594},"_4-exchange-the-code","4. Exchange the code",[318,597,598],{},"Within a few minutes, and once only. A code is single use.",[344,600,602],{"className":346,"code":601,"language":348,"meta":349,"style":349},"curl -X POST https:\u002F\u002Fapi.sporty.plus\u002Foauth2\u002Ftoken \\\n  -H 'Accept: application\u002Fjson' \\\n  -d grant_type=authorization_code \\\n  -d client_id=YOUR_CLIENT_ID \\\n  -d client_secret=YOUR_SECRET \\\n  -d redirect_uri=https:\u002F\u002Fyourapp.example\u002Fcallback \\\n  -d code_verifier=\"$VERIFIER\" \\\n  -d code=THE_CODE\n",[335,603,604,621,635,646,656,666,676,692],{"__ignoreMap":349},[353,605,606,609,612,615,618],{"class":355,"line":356},[353,607,608],{"class":367},"curl",[353,610,611],{"class":371}," -X",[353,613,614],{"class":371}," POST",[353,616,617],{"class":371}," https:\u002F\u002Fapi.sporty.plus\u002Foauth2\u002Ftoken",[353,619,620],{"class":359}," \\\n",[353,622,623,626,628,631,633],{"class":355,"line":411},[353,624,625],{"class":371},"  -H",[353,627,391],{"class":363},[353,629,630],{"class":371},"Accept: application\u002Fjson",[353,632,397],{"class":363},[353,634,620],{"class":359},[353,636,638,641,644],{"class":355,"line":637},3,[353,639,640],{"class":371},"  -d",[353,642,643],{"class":371}," grant_type=authorization_code",[353,645,620],{"class":359},[353,647,649,651,654],{"class":355,"line":648},4,[353,650,640],{"class":371},[353,652,653],{"class":371}," client_id=YOUR_CLIENT_ID",[353,655,620],{"class":359},[353,657,659,661,664],{"class":355,"line":658},5,[353,660,640],{"class":371},[353,662,663],{"class":371}," client_secret=YOUR_SECRET",[353,665,620],{"class":359},[353,667,669,671,674],{"class":355,"line":668},6,[353,670,640],{"class":371},[353,672,673],{"class":371}," redirect_uri=https:\u002F\u002Fyourapp.example\u002Fcallback",[353,675,620],{"class":359},[353,677,679,681,684,686,688,690],{"class":355,"line":678},7,[353,680,640],{"class":371},[353,682,683],{"class":371}," code_verifier=",[353,685,436],{"class":363},[353,687,433],{"class":359},[353,689,436],{"class":363},[353,691,620],{"class":359},[353,693,695,697],{"class":355,"line":694},8,[353,696,640],{"class":371},[353,698,699],{"class":371}," code=THE_CODE\n",[318,701,702,703,706],{},"Omit ",[335,704,705],{},"client_secret"," for a public client.",[344,708,712],{"className":709,"code":710,"language":711,"meta":349,"style":349},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"token_type\": \"Bearer\",\n  \"expires_in\": 3600,\n  \"access_token\": \"eyJ0eXAiOiJKV1Qi...\",\n  \"refresh_token\": \"def5020089ab...\",\n  \"id_token\": \"eyJ0eXAiOiJKV1Qi...\"\n}\n","json",[335,713,714,719,743,759,779,799,816],{"__ignoreMap":349},[353,715,716],{"class":355,"line":356},[353,717,718],{"class":363},"{\n",[353,720,721,724,728,730,733,735,738,740],{"class":355,"line":411},[353,722,723],{"class":363},"  \"",[353,725,727],{"class":726},"spNyl","token_type",[353,729,436],{"class":363},[353,731,732],{"class":363},":",[353,734,430],{"class":363},[353,736,737],{"class":371},"Bearer",[353,739,436],{"class":363},[353,741,742],{"class":363},",\n",[353,744,745,747,750,752,754,757],{"class":355,"line":637},[353,746,723],{"class":363},[353,748,749],{"class":726},"expires_in",[353,751,436],{"class":363},[353,753,732],{"class":363},[353,755,756],{"class":378}," 3600",[353,758,742],{"class":363},[353,760,761,763,766,768,770,772,775,777],{"class":355,"line":648},[353,762,723],{"class":363},[353,764,765],{"class":726},"access_token",[353,767,436],{"class":363},[353,769,732],{"class":363},[353,771,430],{"class":363},[353,773,774],{"class":371},"eyJ0eXAiOiJKV1Qi...",[353,776,436],{"class":363},[353,778,742],{"class":363},[353,780,781,783,786,788,790,792,795,797],{"class":355,"line":658},[353,782,723],{"class":363},[353,784,785],{"class":726},"refresh_token",[353,787,436],{"class":363},[353,789,732],{"class":363},[353,791,430],{"class":363},[353,793,794],{"class":371},"def5020089ab...",[353,796,436],{"class":363},[353,798,742],{"class":363},[353,800,801,803,805,807,809,811,813],{"class":355,"line":668},[353,802,723],{"class":363},[353,804,548],{"class":726},[353,806,436],{"class":363},[353,808,732],{"class":363},[353,810,430],{"class":363},[353,812,774],{"class":371},[353,814,815],{"class":363},"\"\n",[353,817,818],{"class":355,"line":678},[353,819,820],{"class":363},"}\n",[318,822,823,825,826,829,830,833],{},[335,824,548],{}," is present only when you asked for ",[335,827,828],{},"openid",". See\n",[831,832,292],"a",{"href":293},".",[322,835,837],{"id":836},"_5-use-it","5. Use it",[344,839,841],{"className":346,"code":840,"language":348,"meta":349,"style":349},"curl https:\u002F\u002Fapi.sporty.plus\u002Fapi\u002Fpartner\u002Fv1\u002Fclubs\u002Fme \\\n  -H \"Authorization: Bearer $ACCESS_TOKEN\"\n",[335,842,843,852],{"__ignoreMap":349},[353,844,845,847,850],{"class":355,"line":356},[353,846,608],{"class":367},[353,848,849],{"class":371}," https:\u002F\u002Fapi.sporty.plus\u002Fapi\u002Fpartner\u002Fv1\u002Fclubs\u002Fme",[353,851,620],{"class":359},[353,853,854,856,858,861,864],{"class":355,"line":411},[353,855,625],{"class":371},[353,857,430],{"class":363},[353,859,860],{"class":371},"Authorization: Bearer ",[353,862,863],{"class":359},"$ACCESS_TOKEN",[353,865,815],{"class":363},[322,867,869],{"id":868},"_6-refresh","6. Refresh",[318,871,872],{},"Access tokens last an hour; refresh tokens thirty days (a day for a self-registered client).",[344,874,876],{"className":346,"code":875,"language":348,"meta":349,"style":349},"curl -X POST https:\u002F\u002Fapi.sporty.plus\u002Foauth2\u002Ftoken \\\n  -H 'Accept: application\u002Fjson' \\\n  -d grant_type=refresh_token \\\n  -d client_id=YOUR_CLIENT_ID \\\n  -d client_secret=YOUR_SECRET \\\n  -d refresh_token=THE_REFRESH_TOKEN\n",[335,877,878,890,902,911,919,927],{"__ignoreMap":349},[353,879,880,882,884,886,888],{"class":355,"line":356},[353,881,608],{"class":367},[353,883,611],{"class":371},[353,885,614],{"class":371},[353,887,617],{"class":371},[353,889,620],{"class":359},[353,891,892,894,896,898,900],{"class":355,"line":411},[353,893,625],{"class":371},[353,895,391],{"class":363},[353,897,630],{"class":371},[353,899,397],{"class":363},[353,901,620],{"class":359},[353,903,904,906,909],{"class":355,"line":637},[353,905,640],{"class":371},[353,907,908],{"class":371}," grant_type=refresh_token",[353,910,620],{"class":359},[353,912,913,915,917],{"class":355,"line":648},[353,914,640],{"class":371},[353,916,653],{"class":371},[353,918,620],{"class":359},[353,920,921,923,925],{"class":355,"line":658},[353,922,640],{"class":371},[353,924,663],{"class":371},[353,926,620],{"class":359},[353,928,929,931],{"class":355,"line":668},[353,930,640],{"class":371},[353,932,933],{"class":371}," refresh_token=THE_REFRESH_TOKEN\n",[322,935,937],{"id":936},"_7-revoke-when-you-are-done","7. Revoke, when you are done",[344,939,941],{"className":346,"code":940,"language":348,"meta":349,"style":349},"curl -X POST https:\u002F\u002Fapi.sporty.plus\u002Foauth2\u002Ftoken\u002Frevoke \\\n  -d client_id=YOUR_CLIENT_ID \\\n  -d client_secret=YOUR_SECRET \\\n  -d token=THE_ACCESS_TOKEN\n",[335,942,943,956,964,972],{"__ignoreMap":349},[353,944,945,947,949,951,954],{"class":355,"line":356},[353,946,608],{"class":367},[353,948,611],{"class":371},[353,950,614],{"class":371},[353,952,953],{"class":371}," https:\u002F\u002Fapi.sporty.plus\u002Foauth2\u002Ftoken\u002Frevoke",[353,955,620],{"class":359},[353,957,958,960,962],{"class":355,"line":411},[353,959,640],{"class":371},[353,961,653],{"class":371},[353,963,620],{"class":359},[353,965,966,968,970],{"class":355,"line":637},[353,967,640],{"class":371},[353,969,663],{"class":371},[353,971,620],{"class":359},[353,973,974,976],{"class":355,"line":648},[353,975,640],{"class":371},[353,977,978],{"class":371}," token=THE_ACCESS_TOKEN\n",[318,980,981,982,985,986,992],{},"This always answers ",[335,983,984],{},"200",", whatever you send — that is what\n",[831,987,991],{"href":988,"rel":989},"https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc7009",[990],"nofollow","RFC 7009"," requires, so the endpoint cannot be used to\nfind out whether a token is valid.",[994,995,997,1000],"callout",{"icon":996},"i-heroicons-exclamation-triangle",[330,998,999],{},"Name the access token, not the refresh token."," Revoking an access token also revokes the\nrefresh tokens issued with it, which is what \"end this session\" means in practice. A refresh\ntoken on its own cannot currently be named here.",[318,1002,1003,1004,1007],{},"A member can also revoke you at any moment, from ",[330,1005,1006],{},"Authorised applications"," in their profile.\nWhen that happens every token you hold stops working immediately, and you should send them\nthrough the flow again rather than retrying.",[322,1009,1011],{"id":1010},"errors-you-should-expect","Errors you should expect",[507,1013,1014,1024],{},[510,1015,1016],{},[513,1017,1018,1021],{},[516,1019,1020],{},"Error",[516,1022,1023],{},"What happened",[523,1025,1026,1043,1053,1067,1077],{},[513,1027,1028,1033],{},[528,1029,1030],{},[335,1031,1032],{},"invalid_request",[528,1034,1035,1036,1038,1039,1042],{},"Usually a missing or ",[335,1037,341],{}," ",[335,1040,1041],{},"code_challenge",". PKCE with S256 is required.",[513,1044,1045,1050],{},[528,1046,1047],{},[335,1048,1049],{},"invalid_scope",[528,1051,1052],{},"A scope that does not exist, or one this kind of client may not ask for.",[513,1054,1055,1060],{},[528,1056,1057],{},[335,1058,1059],{},"invalid_grant",[528,1061,1062,1063,1066],{},"The code was already spent, expired, or the ",[335,1064,1065],{},"code_verifier"," does not match.",[513,1068,1069,1074],{},[528,1070,1071],{},[335,1072,1073],{},"access_denied",[528,1075,1076],{},"The member said no, or the application is suspended.",[513,1078,1079,1085],{},[528,1080,1081,1084],{},[335,1082,1083],{},"insufficient_scope"," (403)",[528,1086,1087,1088,1091],{},"The token is valid but was not granted this scope. The ",[335,1089,1090],{},"WWW-Authenticate"," header names what is needed.",[318,1093,1094,1095,1098],{},"An unregistered ",[335,1096,1097],{},"redirect_uri"," is never redirected to. You will see the error on Sporty\ninstead — which is the point.",[1100,1101,1102],"style",{},"html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}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 pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":349,"searchDepth":411,"depth":411,"links":1104},[1105,1106,1107,1108,1109,1110,1111,1112],{"id":324,"depth":411,"text":325},{"id":496,"depth":411,"text":497},{"id":569,"depth":411,"text":570},{"id":594,"depth":411,"text":595},{"id":836,"depth":411,"text":837},{"id":868,"depth":411,"text":869},{"id":936,"depth":411,"text":937},{"id":1010,"depth":411,"text":1011},"The whole flow with real requests, from sending someone to Sporty to refreshing a token.","md",null,{},{"icon":278},{"title":1119,"description":1120},"Sporty OAuth authorization code flow with PKCE","A step-by-step walkthrough with curl, including PKCE, refresh and revocation.","CvS-UQuB_r7b90QyPICiNKTk9IFFsd-3mdaxO_tFpZs",[1123,1125],{"title":280,"path":281,"stem":282,"description":1124,"icon":278,"children":-1},"How to get a client id, what a redirect URI may look like, and what \"pending review\" means.",{"title":288,"path":289,"stem":290,"description":1126,"icon":278,"children":-1},"Every scope, what the member is told it means, and which kinds of client may ask for it.",1792420865657]