Apple's MusicKit JS library example runs fine when rendered by Node.js, fails with Django - node.js

For three hours, I've been scratching my head over this.
Apple's MusicKit uses JWT tokens to authenticate.
When I npm start this Node.js example project, I can generate the JWT token, and then authorize Apple Music and collect the user token in response. This works when executing from localhost:8080. Here is a successful pop-up window.
When I launch my Django server locally which also generates valid JWT tokens, running the same exact HTML code with a fresh JWT token, I receive this from Apple: "Problem Connecting: There may be a network issue."
The only error on Apple.com's authorization page, is this: vendor-2c0b12a9762d9af673e21ccd8faf615e.js:2325 Error while processing route: woa Failed to construct 'URL': Invalid URL TypeError: Failed to construct 'URL': Invalid URL
I have confirmed that both applications are generating valid JWT tokens. I can use the tokens generated in my Django application with Postman directly with Apple API, as well as my token from the Node.js app.
I have tried:
Using JWT token from Django in the Node.js app -- works
Using JWT token from Node.js app in Django -- fails still
Allowing all hosts to Django
Allowing all CORS traffic to Django
Hosting page on an HTTPS valid cert. domain vs. locally
Different browser / computer
Accessing the authorization URL directly from Node.js in a new tab -- FAILS
Accessing the authorization URL directly from Django in a new tab -- FAILS
Breaking the JWT token and using that with Django -- FAILS and does not even open the authorization window (console says invalid token, so this further proves the token I use is valid with Django)
From steps 7 / 8, it would appear something in the referral process between when the JS script runs and the pop-up window for authorization appears is failing, as the token is clearly valid.
So what could Django (dev server) be doing that's disrupting this authorization flow? Or am I missing something else?

Okay, so I was right, it had to do with what Node.js server exposed to Apple.com when the request was made, versus what Django did.
It boiled down to the 'Referrer-Policy' policy of the Django server.
By default it is "same site" on Django, which means the referral information is not distributed to Apple.com, so Apple cannot verify the source of the request.
I added the following header to my Django view render:
# Create the render variable
response = render(request, 'apple.html'.format(settings.BASE_DIR), {'apple_developer_token': apple.get_token()})
# Attach the header
response['Referrer-Policy'] = 'origin-when-cross-origin'
# Return the render
return response
It then worked.

Related

In sveltekit, How can I get "load's fetch" from client side code?(like *.svelte)

I'm making private homepage working only for login user.
When user login success, API server return token and save it to cookie.
After that, token was added to all fetch's request header at server-side "handleFetch" hooks.
All works fine with server-side rendering. But At client-side rendering needed position, I can't use "load's fetch" and also can't get token from cookies by default sveltekit functionality.
How can I solve this?

CSRF - invalid token: Capacitorjs App with Node.js backend

In building a mobile app with capacitorjs from a functional web app with Node.js backend that uses the csurf library for the prevention of CSRF attacks, I am getting invalid token errors. The backend is being served from a local machine over http, for now. CORS is setup on the routes under test.
As I understand it, the csurf library provides the client two pieces of information, a secret in the form of a cookie, and a token, both of which the client sends back when making a POST request. The library then checks the expected value of the token with the calculated value (from the secret and from part of the token), and looks for them to match. (Aside: Getting the client to send back the cookies required some effort: I could make it work with a POST using form submission, but not with jQuery $.ajax.) At any rate, I was able to get the client to send back the secret (as a cookie in form submission or otherwise in AJAX POST) and the CSRF-Token, but they don't check out, i.e., the csurf library seems to expect a different answer, for example, here's an example of what the cookie and token look like in one instance:
req.cookies: { _csrf: 'W66Nq2CMcTTJeiFjJRu0gWFH' }
_csrf: 'guOiwkW0-BZguE8LKmYvW3ArKXhUGZuFN_88'
I put some log statements inside the function that checks these two values for correspondence in the csrf library that is used by the csurf library, and got this result:
csrf: secret W66Nq2CMcTTJeiFjJRu0gWFH
csrf: token guOiwkW0-BZguE8LKmYvW3ArKXhUGZuFN_88
csrf: expected guOiwkW0-cWREHVwpgMGiIMoKiSJmc4bA3HE
This kind of result happens whether I make a POST as form submission, or as an AJAX request. For the time being then, I have disabled CSRF protection on these cors routes serving the capacitorjs app.
Another issue that has me concerned is that the folks who wrote this library have this advice:
Don't ever create a GET /csrf route in your app and especially don't
enable CORS on it. Don't send CSRF tokens with API response bodies.
in Understanding CSRF. I am wondering how to send CSRF Tokens to the client, if not in API response bodies!

Node - Unable to Verify the First Certificate / UNABLE_TO_VERIFY_LEAF_SIGNATURE localhost

I have an ASP.NET Core 3.1 web app that I run on my local development machine. This app successfully runs. I can also successfully execute requests to it via Postman. I'm trying to run a test from a Node.js app. This app is using Axios to try to load one of the web pages. The request looks like this:
const result = await axios.get('https://localhost:5001/');
When this request runs, I receive the following error:
Error: unable to verify the first certificate
...
code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE',
...
The fact that I can a) load the url in my browser and b) run the request from Postman leads me to believe there is a config issue with my Node app. I don't know if it's an issue with a) my axios request or b) some app configuration. Oddly, I receive the same error if I try to execute my request against http://localhost:5000/ (i.e. not over HTTPS).
I'm unsure how to resolve this issue though. How do I execute a request via Axios against a web app running on localhost?
You'll need to tell axios/node what signing authorities to trust (your browser and postman will already have several of those set up)
You do that by configuring the https agent in axios - have a look at this answer for an example : How to configure axios to use SSL certificate?
And here are instructions on how to get the bundle from the browser (you'll probably need to use a p7b/pfx or get all certs in the chain): https://medium.com/#menakajain/export-download-ssl-certificate-from-server-site-url-bcfc41ea46a2

JSON Web Token (JWT) is too long to pass through client URL? Node.js and Express authentication

I am trying to use JWT to authenticate a user's email address. I cannot use OAuth because a user will be signing up with their work email and will need to verify using that.
I have added a field to my User model called isVerified. I have used mailgun to send an email to the user when they go to sign up that includes a link to a verification page in the form of http://{client_url}/verification/{userToken} where the userToken is a generated token using JSON web token.... the token is created using only the user's id so there is not a lot of information in the payload.
When the user clicks on this link, they are getting a 404 Not Found error. When I manually shorten the userToken in the url, then it properly connects to the correct React Component...
How do I solve this issue?
UPDATE: I just got rid of all the periods from the JWT token and it is loading like that.... so it seems to not be an issue with the length but with the periods... My react router Route path is "/verification/:userToken" ... how do I get it to not be affected by the periods?
Since this does not trigger your component to be rendered
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjIyLCJpYXQiOjE2MTEwMDY5OTUsImV4cCI6MTYxMTAwODE5NX0.D_-RI_YvE6lyHZFtkMizuHxPs3huIE87D6UKFEywYdg
and this does
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
I would suspect that it somehow worked because you got rid of the dots.
Make sure the "." in the token prevent the url from matching your "verification/token" route ? I mean react is assuming that
"verification/eyxxxx.eyzzzz"
is not a valid route.
Try calling for example "verification/test.test.test" and see if it renders your component.

MongoDB Stitch double encodes redirect URI during Facebook login attempt breaking the login process?

I am trying to use the MongoDB Stitch examples tutorial for the Web based Todo App. I am using Node.JS v10.14.2 on a Ubuntu 18.04 Bionic Beaver Linux station.
When I try to log in with Facebook, the login process fails with Facebook complaining that the redirect URL generated by the Stitch server is not whitelisted, and therefore has been rejected during the attempt to login into Facebook with OAuth. The URL is generated during this code block found in this Node module:
node_modules/mongodb-stitch-browser-core/dist/cjs/core/auth/internal/StitchAuthImpl.js
Here is the code that generates the URL that starts the login process. It calls the Stitch server and the Stitch server generates the correct URL to ask Facebook to login the user. Note, I did modify the code but only to show me the value the getAuthProviderRedirectRoute() call was generating. No other changes were made.
StitchAuthImpl.prototype.loginWithRedirect = function (credential) {
var _this = this;
var _a = this.prepareRedirect(credential), redirectUrl = _a.redirectUrl, state = _a.state;
this.requestClient.getBaseURL().then(function (baseUrl) {
// ROS: We want to see the URL being created - ESM.
let replaceUrl = baseUrl +
_this.browserAuthRoutes.getAuthProviderRedirectRoute(credential, redirectUrl, state, _this.deviceInfo);
_this.jsdomWindow.location.replace(replaceUrl);
});
};
Here is the value of replaceUrl that shows the URL that was generated at this initial stage of the Facebook login process:
replaceUrl = https://stitch.mongodb.com/api/client/v2.0/app/my_stitch_app/auth/providers/oauth2-facebook/login?redirect=http://localhost:8001/&state=<<redacted>>&device=<<redacted>>
Stitch generates this URL for the start of the OAuth Facebook login handshake. As you can see from the code this URL is loaded into the browser's location. The stitch server then generates the URL for the next leg of the OAuth handshake. I have excerpted the redirect_uri query argument from the URL it generates and transfers control to, shown here:
redirect_uri%3Dhttps%253A%252F%252Fstitch.mongodb.com%252Fapi%252Fclient%252Fv2.0%252Fauth%252Fcallback
I then manually decoded the redirect URI because it looked wrong. If you look at the redirect_uri query argument shown above, you will see that the OAuth callback URI has been double encoded with the encodeUri() method. This causes the Facebook OAuth server to reject the callback URI because after being decoded, it looks like the URL shown next to the DECODED ONCE label shown below.
This causes the OAuth handshake to fail because it does not match the URL that you see below marked with the label "DECODED AGAIN".
That value is what I put in the Facebook OAuth "Client OAuth Settings" page in the "Valid OAuth Redirect URIs" section as instructed to by the MongoDB Stitch tutorial. Since the URL has been double encoded, the redirect URI when decoded once, doesn't match the "DECODED AGAIN" value and the login process fails. Obviously I could add the "DECODED ONCE" value to the whitelisted URLs list, but that would just kick the problem down the road because it should look like the completely decoded value in "DECODED AGAIN".
DECODED ONCE:
redirect_uri=https%3A%2F%2Fstitch.mongodb.com%2Fapi%2Fclient%2Fv2.0%2Fauth%2Fcallback
DECODED AGAIN:
redirect_uri=https://stitch.mongodb.com/api/client/v2.0/auth/callback
To recapitulate, when Facebook is asked to login in the user with the URL generated by Stitch, shown below, Facebook fails the process with the error message also shown below:
https://www.facebook.com/login.php?skip_api_login=1&api_key=<<redacted>>&kid_directed_site=0&app_id=<<redacted>>%26redirect_uri%3Dhttps%253A%252F%252Fstitch.mongodb.com%252Fapi%252Fclient%252Fv2.0%252Fauth%252Fcallback
Facebook Error:
URL Blocked
This redirect failed because the redirect URI is not whitelisted in the app’s Client OAuth Settings. Make sure Client and Web OAuth Login are on and add all your app domains as Valid OAuth Redirect URIs.
I have scoured the MongoDB Stitch control panel and I don't see anywhere I may have entered something that would lead to the callback URL being passed to Facebook by Stitch, to be double-encoded. Can anyone tell me what could cause this unwanted behavior and how to fix this?
Thanks for the detailed explanation. I tried reproducing your issue but I was able to login with Facebook successfully.
I also checked the URL that the Stitch server generates when redirecting to Facebook, and it was the exact same double-encoded URI you have in your post. This means that this behavior is expected and should not affect the login flow.
If you look at the full URL, you'll see that the main url (starting at "https://www.facebook.com/login.php") has a query parameter called "next". The "next" parameter is a URL, so it needs to be URL-encoded. This URL passed to "next" has the "redirect_uri" parameter, which is also a URL, so it needs to be URL-encoded as well. Since this is a URL in a URL in a URL, this is why you see the double-encoding.
I formatted the URL with each parameter on a new line, and each sub-URL intended to help demonstrate this:
https://www.facebook.com/login.php
?skip_api_login=1
&api_key=<redacted>
&kid_directed_site=0
&app_id=<redacted>
&signed_next=1
&next=https%3A%2F%2Fwww.facebook.com%2Fdialog%2Foauth
%3Faccess_type%3Doffline
%26client_id%<redacted>
// this is the double encoded URL
%26redirect_uri%3Dhttps%253A%252F%252Fstitch.mongodb.com%252Fapi%252Fclient%252Fv2.0%252Fauth%252Fcallback
%26response_type%3Dcode
%26scope%3Demail%2Bpublic_profile
%26state%3D<redacted>
%26ret%3Dlogin
%26fallback_redirect_uri%<redacted>
&cancel_url=https%3A%2F%2Fstitch.mongodb.com%2Fapi%2Fclient%2Fv2.0%2Fauth%2Fcallback
%3Ferror%3Daccess_denied
%26error_code%3D200
%26error_description%3DPermissions%2Berror
%26error_reason%3Duser_denied
%26state%3D<redacted>
&display=page&locale=en_US
To get Facebook login working, I would ensure the following:
In the Facebook console, make sure this URL is added to the list of "Valid OAuth Redirect URIs":
https://stitch.mongodb.com/api/client/v2.0/auth/callback
In the Stitch console, make sure that your application URL is included in the list of "Redirect URIs" for the Facebook Provider. This should include any trailing slashes.
In your application code, make sure you are calling the following JS code when your redirect URL is hit. This allows the the Stitch client SDK to get the result of the OAuth2 flow performed by the Stitch server:
if (yourStitchClient.auth.hasRedirectResult()) {
return yourStitchClient.auth.handleRedirectResult().then(user => {
console.log("Authenticated as user: " + user);
});
}
Check out https://docs.mongodb.com/stitch/authentication/facebook/ for more explanation on these steps.
If you're still having trouble getting this to work after the above steps, let me know and I'll try to help you debug the issue.

Resources