/
/
/
1<html>
2
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <!-- Required to ensure authentication works behind a reverse proxy -->
7 <meta name="referrer" content="strict-origin-when-cross-origin">
8 <title>Apple Music Sign-in for Music Assistant</title>
9 <link rel="stylesheet" href="./index.css">
10 <script src="./index.js"></script>
11 <script src="https://js-cdn.music.apple.com/musickit/v3/musickit.js" data-web-components async></script>
12 <script>
13 var music = null;
14 var music_user_token = (typeof user_token !== 'undefined' ) ? user_token : "";
15 var music_user_token_timestamp = (typeof user_token_timestamp !== 'undefined' ) ? user_token_timestamp : 0;
16 var callbackConsumed = false;
17 var closing = false;
18 var reloading = false;
19 // token MusicKit already held on page load - may belong to another provider instance
20 var browser_token = "";
21
22 // MusicKit's authorization lives in localStorage, shared by every provider instance on
23 // this origin. Dropping these keys forgets it locally; unauthorize() revokes it at Apple.
24 const MUSICKIT_STORAGE_PREFIX = 'music.';
25 // marks a reload that already dropped the shared session, so we never loop on it
26 const FRESH_SESSION_MARKER = '#new-account';
27
28 // The underlying MA auth helper times-out after fixed period so this window can no longer pass back any data so just close it.
29 // Self closing windows is anti-pattern user experience but better than leaving non-functioning UI presented
30 if (typeof flow_timeout !== 'undefined' && flow_timeout > 0) {
31 setTimeout(sendTokenAndCloseWindow, flow_timeout * 1000);
32 }
33
34 // Attempt to intercept window close and send a request to auth helper before closing the window.
35 // This is not always possible, but we try.
36 window.addEventListener("unload", sendTokenAndCloseWindow, false);
37
38 document.addEventListener('musickitloaded', function () {
39 // MusicKit global is now defined
40 document.getElementById('message').innerHTML = "Apple MusicKit loaded";
41 MusicKit.configure({
42 developerToken: app_token,
43 app: {
44 name: 'Music Assistant',
45 build: (typeof mass_version !== 'undefined' ) ? mass_version : '0.0.0'
46 }
47 }).then(() => {
48 music = MusicKit.getInstance();
49 browser_token = (typeof music.musicUserToken === 'string') ? music.musicUserToken : "";
50 document.getElementById('signin_button').disabled = false;
51 if (isForeignSession()) {
52 // another instance's session: never hand its token to this one
53 if (!sessionForgotten()) {
54 forgetSessionAndReload();
55 return;
56 }
57 document.getElementById('message').innerHTML = "Not signed in";
58 document.getElementById('sub-message').innerHTML = "Sign in with the Apple Account you want to use for this provider.";
59 document.getElementById('signin_button').style.display = "inline-block";
60 document.getElementById('signout_button').style.display = "none";
61 } else if (music.isAuthorized) {
62 // user token must have been issued in last 6 months
63 music_user_token_timestamp = Math.max(music_user_token_timestamp, (Date.now() / 1000) - (3600 * 24 * 180));
64 document.getElementById('message').innerHTML = "Already signed in";
65 document.getElementById('sub-message').innerHTML = "Choose Continue to refresh token or Sign Out to remove token.";
66 document.getElementById('signin_button').innerHTML = "Continue";
67 document.getElementById('signout_button').style.display = "inline-block";
68 } else {
69 document.getElementById('message').innerHTML = "Not signed in";
70 document.getElementById('signin_button').style.display = "inline-block";
71 document.getElementById('signout_button').style.display = "none";
72 }
73 });
74 });
75
76 document.addEventListener("DOMContentLoaded", function () {
77 if (typeof mass_version !== 'undefined' && mass_version) {
78 document.getElementById('mass_version').innerHTML = `v${mass_version} `;
79 }
80 });
81
82 // True when MusicKit is signed in with a session this instance cannot claim as its own.
83 function isForeignSession() {
84 if (!music || !music.isAuthorized) {
85 return false;
86 }
87 return !music_user_token || (browser_token !== "" && browser_token !== music_user_token);
88 }
89
90 function sessionForgotten() {
91 return window.location.hash === FRESH_SESSION_MARKER;
92 }
93
94 // Forget the session locally, leaving the token valid at Apple for other instances.
95 function forgetSessionAndReload() {
96 reloading = true;
97 try {
98 for (const key of Object.keys(window.localStorage)) {
99 if (key.startsWith(MUSICKIT_STORAGE_PREFIX)) {
100 window.localStorage.removeItem(key);
101 }
102 }
103 } catch (error) {
104 console.error("Could not clear the stored MusicKit session: ", error);
105 }
106 window.location.hash = FRESH_SESSION_MARKER;
107 window.location.reload();
108 }
109
110 function sendTokenAndCloseWindow() {
111 if (reloading || closing) {
112 // anti race condition; a reload must not end the flow with an empty token
113 return;
114 }
115 closing = true;
116 if (callbackConsumed) {
117 window.close();
118 return;
119 }
120 var xmlHttp = new XMLHttpRequest();
121 var url = new URL(return_url);
122 var data = null;
123 if (callback_method === "POST") {
124 data = JSON.stringify({'music-user-token': music_user_token, 'music-user-token-timestamp': music_user_token_timestamp});
125 } else {
126 if (music_user_token) {
127 url.searchParams.set('music-user-token', music_user_token);
128 url.searchParams.set('music-user-token-timestamp', music_user_token_timestamp);
129 }
130 }
131 xmlHttp.open(callback_method, url, true);
132 if (data !== null) {
133 // without this the browser labels the JSON body text/plain and the flow drops it
134 xmlHttp.setRequestHeader('Content-Type', 'application/json');
135 }
136 xmlHttp.onreadystatechange = () => {
137 if (xmlHttp.readyState === XMLHttpRequest.DONE) {
138 callbackConsumed = true;
139 if (xmlHttp.status === 200) {
140 document.getElementById('message').innerHTML = "Apple MusicKit token sent to Music Assistant";
141 document.getElementById('sub-message').innerHTML = "You can now close this window.";
142 document.getElementById('signin_button').style.display = "none";
143 document.getElementById('signout_button').style.display = "none";
144 document.getElementById('close_button').innerHTML = "Closingâ¦";
145 setTimeout(() => {
146 window.close();
147 }, 500);
148 } else if (xmlHttp.status >= 400) {
149 console.error("Error sending token to Music Assistant: ", xmlHttp.statusText);
150 document.getElementById('message').innerHTML = "Error sending token to Music Assistant";
151 document.getElementById('sub-message').innerHTML = "Please try again.";
152 document.getElementById('signin_button').style.display = "inline-block";
153 document.getElementById('signout_button').style.display = "none";
154 }
155 }
156 };
157 xmlHttp.send(data);
158 }
159
160 function mkSignInButton() {
161 document.getElementById('signin_button').disabled = true;
162 document.getElementById('message').innerHTML = "Apple Signin window should openâ¦";
163 document.getElementById('sub-message').innerHTML = "If the Apple Music authentication window does not open, please check the MusicKit token and try again.";
164 const foreign_session = isForeignSession();
165 music.authorize().then(function (token) {
166 if (foreign_session && token === browser_token) {
167 // MusicKit reused the session we could not clear: that is another instance's account
168 document.getElementById('message').innerHTML = "Could not start a new Apple Music sign-in";
169 document.getElementById('sub-message').innerHTML = "This browser is still signed in with another Apple Account. Please open this page in a private browser window and sign in there.";
170 document.getElementById('signin_button').disabled = false;
171 return;
172 }
173 music_user_token = token;
174 music_user_token_timestamp = Math.floor(Date.now() / 1000);
175 document.getElementById('message').innerHTML = "Successfully signed in to Apple Music";
176 document.getElementById('close_button').style.display = "inline-block";
177 sendTokenAndCloseWindow();
178 }).catch(function (error) {
179 console.error("Error signing in: ", error);
180 document.getElementById('message').innerHTML = "Error signing in to Apple Music";
181 document.getElementById('sub-message').innerHTML = "Please try again.";
182 document.getElementById('signin_button').disabled = false;
183 document.getElementById('signin_button').style.display = "inline-block";
184 document.getElementById('signout_button').style.display = "none";
185 });
186 }
187
188 function mkSignOutButton() {
189 // only offered for this instance's own session, so revoking at Apple is intended here
190 music.unauthorize();
191 music_user_token = "";
192 music_user_token_timestamp = 0;
193 document.getElementById('signout_button').disabled = true;
194 document.getElementById('message').innerHTML = "This window should closeâ¦";
195 document.getElementById('close_button').style.display = "inline-block";
196 sendTokenAndCloseWindow();
197 }
198
199 function mkCloseButton() {
200 sendTokenAndCloseWindow();
201 }
202
203 function mkSwitchAccountButton() {
204 music_user_token = "";
205 music_user_token_timestamp = 0;
206 forgetSessionAndReload();
207 }
208 </script>
209</head>
210
211<body onunload="sendTokenAndCloseWindow();">
212 <div id="app" class="container">
213 <div class="base-content-wrapper theme-music base-authorization-request"
214 data-test="oauth-authorization-request-third-party">
215 <section class="base-content-wrapper__content">
216 <div class="icons base-authorization-request__icons-container">
217 <div class="base-authorization-request__icon">
218 <div class="base-icon">
219 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
220 x="0px" y="0px" width="76px" height="76px" viewbox="0 0 361 361"
221 style="enable-background:new 0 0 361 361;" xml:space="preserve">
222 <style type="text/css">
223 .st0 {fill-rule: evenodd;clip-rule: evenodd;fill: url('#SVGID_1_');}
224 .st1 {fill-rule: evenodd;clip-rule: evenodd;fill: #FFFFFF;}
225 </style>
226 <lineargradient id="SVGID_1_" gradientunits="userSpaceOnUse" x1="180" y1="358.6047" x2="180" y2="7.7586">
227 <stop offset="0" style="stop-color:#FA233B" />
228 <stop offset="1" style="stop-color:#FB5C74" />
229 </lineargradient>
230 <path class="st0" d="M360,112.61c0-4.3,0-8.6-0.02-12.9c-0.02-3.62-0.06-7.24-0.16-10.86c-0.21-7.89-0.68-15.84-2.08-23.64c-1.42-7.92-3.75-15.29-7.41-22.49c-3.6-7.07-8.3-13.53-13.91-19.14c-5.61-5.61-12.08-10.31-19.15-13.91c-7.19-3.66-14.56-5.98-22.47-7.41c-7.8-1.4-15.76-1.87-23.65-2.08c-3.62-0.1-7.24-0.14-10.86-0.16C255.99,0,251.69,0,247.39,0H112.61c-4.3,0-8.6,0-12.9,0.02c-3.62,0.02-7.24,0.06-10.86,0.16C80.96,0.4,73,0.86,65.2,2.27c-7.92,1.42-15.28,3.75-22.47,7.41c-7.07,3.6-13.54,8.3-19.15,13.91c-5.61,5.61-10.31,12.07-13.91,19.14c-3.66,7.2-5.99,14.57-7.41,22.49c-1.4,7.8-1.87,15.76-2.08,23.64c-0.1,3.62-0.14,7.24-0.16,10.86C0,104.01,0,108.31,0,112.61v134.77c0,4.3,0,8.6,0.02,12.9c0.02,3.62,0.06,7.24,0.16,10.86c0.21,7.89,0.68,15.84,2.08,23.64c1.42,7.92,3.75,15.29,7.41,22.49c3.6,7.07,8.3,13.53,13.91,19.14c5.61,5.61,12.08,10.31,19.15,13.91c7.19,3.66,14.56,5.98,22.47,7.41c7.8,1.4,15.76,1.87,23.65,2.08c3.62,0.1,7.24,0.14,10.86,0.16c4.3,0.03,8.6,0.02,12.9,0.02h134.77c4.3,0,8.6,0,12.9-0.02c3.62-0.02,7.24-0.06,10.86-0.16c7.89-0.21,15.85-0.68,23.65-2.08c7.92-1.42,15.28-3.75,22.47-7.41c7.07-3.6,13.54-8.3,19.15-13.91c5.61-5.61,10.31-12.07,13.91-19.14c3.66-7.2,5.99-14.57,7.41-22.49c1.4-7.8,1.87-15.76,2.08-23.64c0.1-3.62,0.14-7.24,0.16-10.86c0.03-4.3,0.02-8.6,0.02-12.9V112.61z" />
231 <path class="st1" d="M254.5,55c-0.87,0.08-8.6,1.45-9.53,1.64l-107,21.59l-0.04,0.01c-2.79,0.59-4.98,1.58-6.67,3c-2.04,1.71-3.17,4.13-3.6,6.95c-0.09,0.6-0.24,1.82-0.24,3.62c0,0,0,109.32,0,133.92c0,3.13-0.25,6.17-2.37,8.76c-2.12,2.59-4.74,3.37-7.81,3.99c-2.33,0.47-4.66,0.94-6.99,1.41c-8.84,1.78-14.59,2.99-19.8,5.01c-4.98,1.93-8.71,4.39-11.68,7.51c-5.89,6.17-8.28,14.54-7.46,22.38c0.7,6.69,3.71,13.09,8.88,17.82c3.49,3.2,7.85,5.63,12.99,6.66c5.33,1.07,11.01,0.7,19.31-0.98c4.42-0.89,8.56-2.28,12.5-4.61c3.9-2.3,7.24-5.37,9.85-9.11c2.62-3.75,4.31-7.92,5.24-12.35c0.96-4.57,1.19-8.7,1.19-13.26l0-116.15c0-6.22,1.76-7.86,6.78-9.08c0,0,88.94-17.94,93.09-18.75c5.79-1.11,8.52,0.54,8.52,6.61l0,79.29c0,3.14-0.03,6.32-2.17,8.92c-2.12,2.59-4.74,3.37-7.81,3.99c-2.33,0.47-4.66,0.94-6.99,1.41c-8.84,1.78-14.59,2.99-19.8,5.01c-4.98,1.93-8.71,4.39-11.68,7.51c-5.89,6.17-8.49,14.54-7.67,22.38c0.7,6.69,3.92,13.09,9.09,17.82c3.49,3.2,7.85,5.56,12.99,6.6c5.33,1.07,11.01,0.69,19.31-0.98c4.42-0.89,8.56-2.22,12.5-4.55c3.9-2.3,7.24-5.37,9.85-9.11c2.62-3.75,4.31-7.92,5.24-12.35c0.96-4.57,1-8.7,1-13.26V64.46C263.54,58.3,260.29,54.5,254.5,55z" />
232 </svg>
233 <p class="base-icon__label">Apple Music</p>
234 </div>
235 </div>
236 <div class="base-authorization-request__arrows"></div>
237 <div class="base-authorization-request__icon">
238 <div class="base-icon">
239 <img src="data:image/png;base64,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"
240 height="76px" width="76px">
241 <p class="base-icon__label">Music Assistant</p>
242 </div>
243 </div>
244 </div>
245 <h1 class="base-content-wrapper__title typography-label">
246 <span id="message">Apple MusicKit is loadingâ¦</span>
247 </h1>
248 <p id="sub-message" class="base-content-wrapper__description typography-body-tight">
249 Sign in with Apple to allow Music Assistant to access your Apple Music account.</p>
250 <p>
251 <button id="signin_button"
252 class="button button-block button-elevated button-primary base-button base-button--primary base-content-wrapper__button"
253 onclick="mkSignInButton();" disabled>Sign In</button>
254 </p>
255 <p>
256 <button id="signout_button"
257 class="button button-block button-elevated button-primary base-button base-button--primary base-content-wrapper__button"
258 onclick="mkSignOutButton();" style="display: none">Sign Out</button>
259 </p>
260 <p>
261 <button id="close_button"
262 class="button button-block button-elevated button-secondary base-button base-button--secondary base-content-wrapper__button"
263 onclick="mkCloseButton();">Close</button>
264 </p>
265 </section>
266 <div class="privacy-summary__link-container">
267 <a class="privacy-summary__link-text privacy-summary__link-text--margin-top typography-caption"
268 onclick="mkSwitchAccountButton(); return false;" href="#">Use a different Apple Account</a>
269 </div>
270 <footer class="base-footer">
271 <p class="base-footer__copyright">© 2025 Music Assistant <span id="mass_version"></span>- Part of the
272 <a href="https://www.openhomefoundation.org" target="_blank">Open Home Foundation</a>. Support us on
273 <a href="https://github.com/sponsors/music-assistant" target="_blank">GitHub</a>.
274 </p>
275 </footer>
276 </div>
277 </div>
278</body>
279</html>
280