Spotify.NET/docs/authorization_code/index.html
2022-03-19 19:29:23 +00:00

27 lines
24 KiB
HTML

<!doctype html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="generator" content="Docusaurus v2.0.0-beta.4">
<title data-react-helmet="true">Authorization Code | SpotifyAPI-NET</title><meta data-react-helmet="true" property="og:url" content="https://johnnycrazy.github.io/SpotifyAPI-NET/docs/authorization_code"><meta data-react-helmet="true" name="docusaurus_locale" content="en"><meta data-react-helmet="true" name="docusaurus_version" content="current"><meta data-react-helmet="true" name="docusaurus_tag" content="docs-default-current"><meta data-react-helmet="true" property="og:title" content="Authorization Code | SpotifyAPI-NET"><meta data-react-helmet="true" name="description" content="This flow is suitable for long-running applications in which the user grants permission only once. It provides an access token that can be refreshed. Since the token exchange involves sending your secret key, perform this on a secure location, like a backend service, and not from a client such as a browser or from a mobile app."><meta data-react-helmet="true" property="og:description" content="This flow is suitable for long-running applications in which the user grants permission only once. It provides an access token that can be refreshed. Since the token exchange involves sending your secret key, perform this on a secure location, like a backend service, and not from a client such as a browser or from a mobile app."><link data-react-helmet="true" rel="shortcut icon" href="/SpotifyAPI-NET/img/favicon.ico"><link data-react-helmet="true" rel="canonical" href="https://johnnycrazy.github.io/SpotifyAPI-NET/docs/authorization_code"><link data-react-helmet="true" rel="alternate" href="https://johnnycrazy.github.io/SpotifyAPI-NET/docs/authorization_code" hreflang="en"><link data-react-helmet="true" rel="alternate" href="https://johnnycrazy.github.io/SpotifyAPI-NET/docs/authorization_code" hreflang="x-default"><link rel="stylesheet" href="/SpotifyAPI-NET/assets/css/styles.834af7f3.css">
<link rel="preload" href="/SpotifyAPI-NET/assets/js/runtime~main.0fc40eeb.js" as="script">
<link rel="preload" href="/SpotifyAPI-NET/assets/js/main.29a3befa.js" as="script">
</head>
<body>
<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){var t=null;try{t=localStorage.getItem("theme")}catch(t){}return t}();t(null!==e?e:"light")}()</script><div id="__docusaurus">
<div><a href="#" class="skipToContent_1oUP">Skip to main content</a></div><nav class="navbar navbar--fixed-top"><div class="navbar__inner"><div class="navbar__items"><button aria-label="Navigation bar toggle" class="navbar__toggle clean-btn" type="button" tabindex="0"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><a class="navbar__brand" href="/SpotifyAPI-NET/"><img src="/SpotifyAPI-NET/img/logo.svg" alt="SpotifyAPI-NET" class="themedImage_1VuW themedImage--light_3UqQ navbar__logo"><img src="/SpotifyAPI-NET/img/logo.svg" alt="SpotifyAPI-NET" class="themedImage_1VuW themedImage--dark_hz6m navbar__logo"><b class="navbar__title">SpotifyAPI-NET</b></a><div class="navbar__item dropdown dropdown--hoverable"><a class="navbar__item navbar__link">Docs</a><ul class="dropdown__menu"><li><a class="dropdown__link" href="/SpotifyAPI-NET/docs/introduction">6.X (current)</a></li><li><a class="dropdown__link" href="/SpotifyAPI-NET/docs/5.1.1/home">5.1.1</a></li></ul></div></div><div class="navbar__items navbar__items--right"><a href="https://github.com/JohnnyCrazy/SpotifyAPI-NET" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link"><span>GitHub<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_3J9K"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></span></a><div class="react-toggle toggle_3Zt9 react-toggle--disabled"><div class="react-toggle-track" role="button" tabindex="-1"><div class="react-toggle-track-check"><span class="toggle_71bT">🌜</span></div><div class="react-toggle-track-x"><span class="toggle_71bT">🌞</span></div><div class="react-toggle-thumb"></div></div><input type="checkbox" class="react-toggle-screenreader-only" aria-label="Switch between dark and light mode"></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div></nav><div class="main-wrapper docs-wrapper doc-page"><div class="docPage_31aa"><button class="clean-btn backToTopButton_35hR" type="button" title="Scroll to top"><svg viewBox="0 0 24 24" width="28"><path d="M7.41 15.41L12 10.83l4.59 4.58L18 14l-6-6-6 6z" fill="currentColor"></path></svg></button><aside class="docSidebarContainer_3Kbt"><div class="sidebar_15mo"><nav class="menu thin-scrollbar menu_Bmed menuWithAnnouncementBar_2WvA"><ul class="menu__list"><li class="menu__list-item"><a class="menu__link menu__link--sublist menu__link--active" href="#">SpotifyAPI-NET</a><ul style="display:block;overflow:visible;height:auto" class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/SpotifyAPI-NET/docs/introduction">Introduction</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/SpotifyAPI-NET/docs/getting_started">Getting Started</a></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#" tabindex="0">Guides</a></li><li class="menu__list-item"><a class="menu__link menu__link--sublist menu__link--active" href="#" tabindex="0">Authentication Guides</a><ul style="display:block;overflow:visible;height:auto" class="menu__list"><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/SpotifyAPI-NET/docs/auth_introduction">Introduction</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/SpotifyAPI-NET/docs/client_credentials">Client Credentials</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/SpotifyAPI-NET/docs/implicit_grant">Implicit Grant</a></li><li class="menu__list-item"><a aria-current="page" class="menu__link menu__link--active active" tabindex="0" href="/SpotifyAPI-NET/docs/authorization_code">Authorization Code</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/SpotifyAPI-NET/docs/pkce">PKCE</a></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/SpotifyAPI-NET/docs/token_swap">Token Swap</a></li></ul></li><li class="menu__list-item"><a class="menu__link" tabindex="0" href="/SpotifyAPI-NET/docs/showcase">Showcase</a></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#" tabindex="0">Examples</a></li><li class="menu__list-item menu__list-item--collapsed"><a class="menu__link menu__link--sublist" href="#" tabindex="0">Migration Guides</a></li></ul></li></ul></nav></div></aside><main class="docMainContainer_3ufF"><div class="container padding-top--md padding-bottom--lg"><div class="row"><div class="col docItemCol_3FnS"><div class="docItemContainer_33ec"><article><span class="badge badge--secondary">Version: 6.X</span><div class="tocCollapsible_1PrD tocMobile_3Hoh"><button type="button" class="clean-btn tocCollapsibleButton_2O1e">On this page</button></div><div class="markdown"><header><h1 class="h1Heading_27L5">Authorization Code</h1></header><blockquote><p>This flow is suitable for long-running applications in which the user grants permission only once. It provides an access token that can be refreshed. Since the token exchange involves sending your secret key, perform this on a secure location, like a backend service, and not from a client such as a browser or from a mobile app.</p></blockquote><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2LWZ" id="existing-web-server"></a>Existing Web-Server<a class="hash-link" href="#existing-web-server" title="Direct link to heading">#</a></h2><p>If you are already in control of a Web-Server (like <code>ASP.NET</code>), you can start the flow by generating a login uri:</p><div class="codeBlockContainer_K1bP"><div class="codeBlockContent_hGly csharp"><pre tabindex="0" class="prism-code language-csharp codeBlock_23N8 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_39YC"><span class="token-line" style="color:#bfc7d5"><span class="token plain">// Make sure &quot;http://localhost:5000&quot; is in your applications redirect URIs!</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">var loginRequest = new LoginRequest(</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> new Uri(&quot;http://localhost:5000&quot;),</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> &quot;ClientId&quot;,</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> LoginRequest.ResponseType.Code</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">)</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> Scope = new[] { Scopes.PlaylistReadPrivate, Scopes.PlaylistReadCollaborative }</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">};</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">var uri = loginRequest.ToUri();</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">// Redirect user to uri via your favorite web-server</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_Ue-o clean-btn">Copy</button></div></div><p>When the user is redirected to the generated uri, they will have to login with their Spotify account and confirm that your application wants to access their user data. Once confirmed, they will be redirected to <code>http://localhost:5000</code> and a <code>code</code> parameter is attached to the query. This <code>code</code> has to be exchanged for an <code>access_token</code> and <code>refresh_token</code>:</p><div class="codeBlockContainer_K1bP"><div class="codeBlockContent_hGly csharp"><pre tabindex="0" class="prism-code language-csharp codeBlock_23N8 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_39YC"><span class="token-line" style="color:#bfc7d5"><span class="token plain">// This method should be called from your web-server when the user visits &quot;http://localhost:5000&quot;</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">public Task GetCallback(string code)</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> var response = await new OAuthClient().RequestToken(</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> new AuthorizationCodeTokenRequest(&quot;ClientId&quot;, &quot;ClientSecret&quot;, code, &quot;http://localhost:5000&quot;)</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> );</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> var spotify = new SpotifyClient(response.AccessToken);</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> // Also important for later: response.RefreshToken</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_Ue-o clean-btn">Copy</button></div></div><p>If the token expires at some point (check via <code>response.IsExpired</code>), you can refresh it:</p><div class="codeBlockContainer_K1bP"><div class="codeBlockContent_hGly csharp"><pre tabindex="0" class="prism-code language-csharp codeBlock_23N8 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_39YC"><span class="token-line" style="color:#bfc7d5"><span class="token plain">var newResponse = await new OAuthClient().RequestToken(</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> new AuthorizationCodeRefreshRequest(&quot;ClientId&quot;, &quot;ClientSecret&quot;, response.RefreshToken)</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">);</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">var spotify = new SpotifyClient(newResponse.AccessToken);</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_Ue-o clean-btn">Copy</button></div></div><p>You can also let the <code>AuthorizationCodeAuthenticator</code> take care of the refresh part:</p><div class="codeBlockContainer_K1bP"><div class="codeBlockContent_hGly csharp"><pre tabindex="0" class="prism-code language-csharp codeBlock_23N8 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_39YC"><span class="token-line" style="color:#bfc7d5"><span class="token plain">var response = await new OAuthClient().RequestToken(</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> new AuthorizationCodeTokenRequest(&quot;ClientId&quot;, &quot;ClientSecret&quot;, code, &quot;http://localhost:5000&quot;)</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">);</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">var config = SpotifyClientConfig</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> .CreateDefault()</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> .WithAuthenticator(new AuthorizationCodeAuthenticator(&quot;ClientId&quot;, &quot;ClientSecret&quot;, response));</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">var spotify = new SpotifyClient(config);</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_Ue-o clean-btn">Copy</button></div></div><p>For a real example, have a look at <a href="https://github.com/JohnnyCrazy/SpotifyAPI-NET/tree/master/SpotifyAPI.Web.Examples/Example.ASP" target="_blank" rel="noopener noreferrer">Example.ASP</a>. This also uses the great package <code>AspNet.Security.OAuth.Spotify</code> which takes care of the OAuth flow inside of <code>ASP.NET</code>.</p><h2><a aria-hidden="true" tabindex="-1" class="anchor enhancedAnchor_2LWZ" id="using-spotifywebauth"></a>Using Spotify.Web.Auth<a class="hash-link" href="#using-spotifywebauth" title="Direct link to heading">#</a></h2><p>For cross-platform CLI and desktop apps (non <code>UWP</code> apps), <code>Spotify.Web.Auth</code> can be used to supply a small embedded Web Server for the code retrieval.</p><div class="admonition admonition-warning alert alert--danger"><div class="admonition-heading"><h5><span class="admonition-icon"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 12 16"><path fill-rule="evenodd" d="M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"></path></svg></span>warning</h5></div><div class="admonition-content"><p>Your client secret will be exposed when embedded in a desktop/CLI app. This can be abused and is not prefered. If possible, let the user create an application in the Spotify dashboard or let a server handle the Spotify communication.</p></div></div><div class="codeBlockContainer_K1bP"><div class="codeBlockContent_hGly csharp"><pre tabindex="0" class="prism-code language-csharp codeBlock_23N8 thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_39YC"><span class="token-line" style="color:#bfc7d5"><span class="token plain">private static EmbedIOAuthServer _server;</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">public static async Task Main()</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> // Make sure &quot;http://localhost:5000/callback&quot; is in your spotify application as redirect uri!</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> _server = new EmbedIOAuthServer(new Uri(&quot;http://localhost:5000/callback&quot;), 5000);</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> await _server.Start();</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> _server.AuthorizationCodeReceived += OnAuthorizationCodeReceived;</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> _server.ErrorReceived += OnErrorReceived;</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> var request = new LoginRequest(_server.BaseUri, &quot;ClientId&quot;, LoginRequest.ResponseType.Code)</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> {</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> Scope = new List&lt;string&gt; { Scopes.UserReadEmail }</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> };</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> BrowserUtil.Open(request.ToUri());</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">private static async Task OnAuthorizationCodeReceived(object sender, AuthorizationCodeResponse response)</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> await _server.Stop();</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> var config = SpotifyClientConfig.CreateDefault();</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> var tokenResponse = await new OAuthClient(config).RequestToken(</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> new AuthorizationCodeTokenRequest(</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> &quot;ClientId&quot;, &quot;ClientSecret&quot;, response.Code, new Uri(&quot;http://localhost:5000/callback&quot;)</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> )</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> );</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> var spotify = new SpotifyClient(tokenResponse.AccessToken);</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> // do calls with Spotify and save token?</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block">
</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">private static async Task OnErrorReceived(object sender, string error, string state)</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">{</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> Console.WriteLine($&quot;Aborting authorization, error received: {error}&quot;);</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> await _server.Stop();</span></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">}</span></span></code></pre><button type="button" aria-label="Copy code to clipboard" class="copyButton_Ue-o clean-btn">Copy</button></div></div><p>For real examples, have a look at <a href="https://github.com/JohnnyCrazy/SpotifyAPI-NET/tree/master/SpotifyAPI.Web.Examples/Example.CLI.PersistentConfig" target="_blank" rel="noopener noreferrer">Example.CLI.PersistentConfig</a> and <a href="https://github.com/JohnnyCrazy/SpotifyAPI-NET/tree/master/SpotifyAPI.Web.Examples/Example.CLI.CustomHTML" target="_blank" rel="noopener noreferrer">Example.CLI.CustomHTML</a></p></div><footer class="row docusaurus-mt-lg"><div class="col"><a href="https://github.com/JohnnyCrazy/SpotifyAPI-NET/edit/master/SpotifyAPI.Docs/docs/authorization_code.md" target="_blank" rel="noreferrer noopener"><svg fill="currentColor" height="20" width="20" viewBox="0 0 40 40" class="iconEdit_2_ui" aria-hidden="true"><g><path d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"></path></g></svg>Edit this page</a></div><div class="col lastUpdated_3DPF">Last updated on <b><time datetime="2022-03-19T19:27:57.000Z">3/19/2022</time></b> by <b>dependabot[bot]</b></div></footer></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="Docs pages navigation"><div class="pagination-nav__item"><a class="pagination-nav__link" href="/SpotifyAPI-NET/docs/implicit_grant"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">« Implicit Grant</div></a></div><div class="pagination-nav__item pagination-nav__item--next"><a class="pagination-nav__link" href="/SpotifyAPI-NET/docs/pkce"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">PKCE »</div></a></div></nav></div></div><div class="col col--3"><div class="tableOfContents_35-E thin-scrollbar"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#existing-web-server" class="table-of-contents__link">Existing Web-Server</a></li><li><a href="#using-spotifywebauth" class="table-of-contents__link">Using Spotify.Web.Auth</a></li></ul></div></div></div></div></main></div></div><footer class="footer footer--dark"><div class="container"><div class="footer__bottom text--center"><div class="footer__copyright">Copyright © 2022 Jonas Dellinger. Built with Docusaurus.</div></div></div></footer></div>
<script src="/SpotifyAPI-NET/assets/js/runtime~main.0fc40eeb.js"></script>
<script src="/SpotifyAPI-NET/assets/js/main.29a3befa.js"></script>
</body>
</html>