New
Jul 7, 2020 3:38 AM
#1
Hi! As you might have noticed, the new MAL API uses OAuth 2.0 to authorise all the HTTP requests. It is no longer possible to provide your username and password to access the endpoints. Since I believe that many users have a little or no knowledge of the OAuth protocol, I wrote a small guide to let you start experimenting with the new API as quickly as possible. You can find it here: myanimelist.net/blog.php?eid=835707. (The guide is based on the official documentation which you can read by clicking here) |
XinilJul 7, 2020 11:12 PM
Jul 7, 2020 5:01 AM
#2
This is actually not quite true, we have undocumented endpoint for login and password auth (it is quite stable, I'm using it since 2018, never had any problems) EDIT: I changed my mind EDIT: I decided to remove endpoint description from here, maybe not sharing it will extend its lifespan 😆 Keep in mind that undocumented endpoints can disappear out of existence at any point, but as I stated I'm using this one for quite some time already |
PolyMeilexJul 7, 2020 5:16 AM
Jul 7, 2020 5:08 AM
#3
PolyMeilex said: This is actually not quite true, we have undocumented endpoint for login and password auth (it is quite stable, I'm using it since 2018, never had any problems) I avoided putting any undocumented endpoint in the guide so that people don't start building their applications on API functions which may be removed in the future without any prior notice. |
Jul 7, 2020 5:26 AM
#4
Even when manually building the URL it keeps saying my client is invalid and prompts me with a plain login form.{"error":"invalid_client","message":"Client authentication failed"} My ID shows as "Published" - is there a further validation step required? Edit: Created a second app. That client key actually works... Edit2: This error appears as soon as I add more than one redirect URL - bug? Edit3: It's no longer happening consistently so take that info with a grain of salt but there is certainly odd behavior with the redirect URLs including the order in which they are saved/displayed (was able to add them back in)... |
sp1Jul 7, 2020 5:53 AM
Jul 7, 2020 6:43 AM
#5
sp1 said: Edit2: This error appears as soon as I add more than one redirect URL - bug? Edit3: It's no longer happening consistently so take that info with a grain of salt but there is certainly odd behavior with the redirect URLs including the order in which they are saved/displayed (was able to add them back in)... It seems like there's currently something wrong with the redirection. Hopefully, it will be fixed soon. |
Jul 7, 2020 7:13 AM
#6
Thanks for looking into it! I was running a web based script before the MAL API died... seems like CORS isn't allowed: Access to XMLHttpRequest at 'https://myanimelist.net/v1/oauth2/token' from origin 'XXXXX' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Could this be changed? Glancing at https://tools.ietf.org/id/draft-ietf-oauth-browser-based-apps-02.html the PKCE method should suffice as protection? Otherwise I need to workaround that restriction. |
sp1Jul 7, 2020 7:24 AM
Jul 7, 2020 7:22 AM
#7
Sabem dizer se vai ser lançado Hoje ou amanhã no Google play store? Ou só por esse método mesmo? |
Jul 7, 2020 7:32 AM
#8
sp1 said: I was running a web based script before the MAL API died... seems like CORS isn't allowed: Access to XMLHttpRequest at 'https://myanimelist.net/v1/oauth2/token' from origin 'XXXXX' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Can I ask you how did you get that error? On what kind of web script were you working on? |
Jul 7, 2020 7:35 AM
#9
Zicornis said: Sabem dizer se vai ser lançado Hoje ou amanhã no Google play store? Ou só por esse método mesmo? MAL's mobile app is not going to be released anytime soon. The public API was published today, but the app should come out later this year. |
Jul 7, 2020 7:39 AM
#10
Btw, when I set my app type to something different than "web" I no longer need client_secret. So back-end infrastructure becomes useless in this scenario, or did I misunderstood something? I just handled my redirect with simple js on a static webpage. I believe that backend is not needed for android or ios usage, am I right? or am I terribly wrong? I don't have OAuth knolage so I decided to ask, just in case EDIT: I know that it's my responsibility to make sure that my users do not exceed my monthly request quota, but let's say that I don't care about it that much |
PolyMeilexJul 7, 2020 7:52 AM
Jul 7, 2020 7:42 AM
#11
ZeroCrystal said: sp1 said: I was running a web based script before the MAL API died... seems like CORS isn't allowed: Access to XMLHttpRequest at 'https://myanimelist.net/v1/oauth2/token' from origin 'XXXXX' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Can I ask you how did you get that error? On what kind of web script were you working on? Sure. I get the error inside the browser console when trying to get the access token for the user (so the final step in the auth flow). As of now he gets redirected back to the same page (depending on how I handle this along side the second API that requires auth this might change) This can be bypassed with a browser extension which allows the CORS regardless but that isn't really a general solution (if I do that I get the access token successfully). From my understanding this should be gone once it's allowed in the header. The script does sync show and movie data between MAL and https://trakt.tv/. Nothing is saved on my end so the sync has to be triggered by the user when he wants to do it. Was mostly done with PHP and uses the trakt REST API and had the old MAL XML one active. It's basically requesting user data from either end and fills in the gaps. Also uses trakt, MAL, TVDB and TMDB APIs for some backend/image stuff (periodical title updates, etc.). Sadly there is no PHP wrapper for Oauth2 & PKCE which is why I was going for JS for the new MAL one. Hope that is the info you were looking for. |
sp1Jul 7, 2020 8:12 AM
Jul 7, 2020 8:21 AM
#12
PolyMeilex said: Btw, when I set my app type to something different than "web" I no longer need client_secret. So back-end infrastructure becomes useless in this scenario, or did I misunderstood something? Yes, you can catch the Access Token directly in the mobile app if you don't have a Client Secret (i.e. you selected "Android", "iOS", or "Other" as App Type). As you pointed out, once you give the Access Token (and maybe the Refresh Token) to the user, they might abuse it. It's up to you to decide which strategy you should take. I will expand this point in the guide as it needs some special considerations. (EDIT: I adjusted the guide) |
ZeroCrystalJul 7, 2020 9:28 AM
Jul 7, 2020 8:31 AM
#13
ZeroCrystal said: Yes, you can catch the Access Token directly in the mobile app if you don't have a Client Secret (i.e. you selected "Android", "iOS", or "Other" as App Type). Ok so I understood it correctly, thank you for confirmation. |
Jul 7, 2020 9:59 AM
#14
sp1 said: I get the error inside the browser console when trying to get the access token for the user (so the final step in the auth flow). As of now he gets redirected back to the same page (depending on how I handle this along side the second API that requires auth this might change) This can be bypassed with a browser extension which allows the CORS regardless but that isn't really a general solution (if I do that I get the access token successfully). From my understanding this should be gone once it's allowed in the header. Did you try with JSONP? Like (source): $.ajax({ type: 'POST', crossDomain: true, dataType: 'jsonp', url: '...', success: function(jsondata) { } }) You can also find some tips on how to circumvent CORS here. |
ZeroCrystalJul 7, 2020 10:05 AM
Jul 7, 2020 10:57 AM
#15
Jul 7, 2020 11:06 AM
#16
ZeroCrystal said: Did you try with JSONP? Like (source) You can also find some tips on how to circumvent CORS here. Thanks for the reply but this is already workaround territory imho. https://developer.okta.com/blog/2019/05/01/is-the-oauth-implicit-flow-dead and https://tools.ietf.org/id/draft-ietf-oauth-browser-based-apps-02.html both suggest that CORS can be used with PKCE - maybe for the devs to look at. Going to get this setup by temporarily allowing it for me in testing. Once I've updated everything I'll see what my options are. Edit: Did it plain in PHP and it works there without doing a CORS. So this is resolved for me. |
sp1Jul 8, 2020 8:54 AM
Jul 7, 2020 11:11 PM
#17
Thanks for this super helpful guide @zerocrystal! I'm going to sticky it if you don't mind? |
Jul 7, 2020 11:43 PM
#18
Does anyone know why I keep getting this error when trying to exchange the authorization code for the access token: { "error": "unsupported_grant_type", "message": "The authorization grant type is not supported by the authorization server.", "hint": "Check the `grant_type` parameter" } I'm using Scheme 1 since I don't have a client_secret, and I definitely am putting in the param "grant_type" with the value "authorization_code" like so: "https://myanimelist.net/v1/oauth2/token?client_id=MY_CLIENT_ID&grant_type=authorization_code&code=MY_AUTH_CODE&code_verifier=MY_CODE_VERIFIER" |
Jul 8, 2020 2:40 AM
#19
Flash0793 said: Does anyone know why I keep getting this error when trying to exchange the authorization code for the access token: { "error": "unsupported_grant_type", "message": "The authorization grant type is not supported by the authorization server.", "hint": "Check the `grant_type` parameter" } I'm using Scheme 1 since I don't have a client_secret, and I definitely am putting in the param "grant_type" with the value "authorization_code" like so: "https://myanimelist.net/v1/oauth2/token?client_id=MY_CLIENT_ID&grant_type=authorization_code&code=MY_AUTH_CODE&code_verifier=MY_CODE_VERIFIER" Just a hunch, but is your verifier the same as your challenge? If it's not, it should be. |
Jul 8, 2020 2:50 AM
#20
Xinil said: Thanks for this super helpful guide @zerocrystal! I'm going to sticky it if you don't mind? I don't mind, go ahead. ;-) |
Jul 8, 2020 5:20 AM
#21
Flash0793 said: Does anyone know why I keep getting this error when trying to exchange the authorization code for the access token: { "error": "unsupported_grant_type", "message": "The authorization grant type is not supported by the authorization server.", "hint": "Check the `grant_type` parameter" } The "unsupported_grant_type" error is used as a catch-all handler (or it's simply the first parameter to be parsed by the server). For example, if you send a request with no parameters, you would still get the exact same error. Your problem is that you're sending the parameters as part of the query string. Instead, they should be encoded inside the body of the POST request (they're form URL encoded). Flash0793 said: I'm using Scheme 1 since I don't have a client_secret You can use both schemes even if you don't have a Client Secret. In scheme 2, you can simply omit the client_secret parameter if you don't have one. |
Jul 8, 2020 6:22 PM
#22
ZeroCrystal said: Your problem is that you're sending the parameters as part of the query string. Instead, they should be encoded inside the body of the POST request (they're form URL encoded). Got it! Thanks for the help. |
Jul 9, 2020 7:33 AM
#23
Hello, I was wondering if anyone could help me with an issue I am having in regards to getting the access token. When using python I did not encounter this error and was able to access the API, but now using Javascript I get the error "blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.". Here is my code (don't hate I am noob): async function malGetAccessToken(){ const payload = { 'client_id': mal_client_id, 'client_secret': mal_client_secret, 'code': mal_code, 'code_verifier': code_verifier, 'grant_type': mal_grant_type } const params = { method:"POST", body: JSON.stringify(payload) }; const response = await fetch(mal_token_url, params); const data = await response.json(); console.log(data); } Any advice even if its not relevant to the error would be helpful :), thanks! |
Jul 9, 2020 8:12 AM
#24
x_Acnologia said: When using python I did not encounter this error and was able to access the API, but now using Javascript I get the error "blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.". Maybe you should take a look at this article. |
Jul 22, 2020 6:45 PM
#25
hiya, i'm new to using APIs and stuff and trying to develop an android app i'm coding in python using the requests module and made it to the 2nd step on the guide you had posted i'm not sure how to take it from here. i hit the URL with the parameters for response_type, client_id, and code_challenge, and the GET request goes through successfully; but i assume i would need to be able to log in and hit the allow button from the URL that is returned, right? or else i won't be able to get the user authorization code returned? do i need to develop my app to the point where i can display webpages first? i was thinking i could work with the API first to understand how i want to develop the rest of the app but i don't understand how to get past this step... i'm sorry if this is too nooby of a question ;_______; |
Jul 23, 2020 6:27 AM
#26
capnsquishy said: hiya, i'm new to using APIs and stuff and trying to develop an android app i'm coding in python using the requests module and made it to the 2nd step on the guide you had posted i'm not sure how to take it from here. i hit the URL with the parameters for response_type, client_id, and code_challenge, and the GET request goes through successfully; but i assume i would need to be able to log in and hit the allow button from the URL that is returned, right? or else i won't be able to get the user authorization code returned? do i need to develop my app to the point where i can display webpages first? i was thinking i could work with the API first to understand how i want to develop the rest of the app but i don't understand how to get past this step... i'm sorry if this is too nooby of a question ;_______; You can generate a string representing the URL in step 2 and print it to the console. Then you could proceed with the URL in your Browser, then Login and then copy the code from the URL you get redirected to. Then you could proceed with step 3. Or there is some way to get the generated URL from the requests.get function call or the resulting object, but i didn't work with the Python requests module yet. |
Jul 23, 2020 6:42 AM
#27
capnsquishy said: i assume i would need to be able to log in and hit the allow button from the URL that is returned, right? or else i won't be able to get the user authorization code returned? do i need to develop my app to the point where i can display webpages first? i was thinking i could work with the API first to understand how i want to develop the rest of the app but i don't understand how to get past this step... To complete the authorisation procedure, your mobile app needs to show the webpage to the user. First, he has to login (if needed), and then he must review the request and explicitly approve it. Some kind of web browser is required. Opening the URL inside a browser is easy: you can use a Chrome Custom Tab or directly opening the default browser. Obtaining the response from MAL's servers is slightly more difficult; the OAuth protocol requires a redirect URL where any approved request will be forwarded. The IETF recommends native and mobile app developers to define a custom URI scheme (deep link) to catch the authorisation code from the browser (e.g. myapp://auth). Implementing it is easier than it might sounds, you can find more clicking here. Alternatively, you can run a local web server waiting for the authorisation code on localhost, but it's probably more complex than needed. WebViews are discouraged due to UX and security reasons. For testing purpose, as @SAOFag said, you can simply print or display the URL, opening it inside your browser, and copy-pasting the authorisation code. |
Jul 25, 2020 8:33 AM
#28
Thanks a lot for this guide. I didn't know how to use MAL API, now that's totally clear |
Aug 2, 2020 2:30 AM
#29
I'm getting this error everytime I send a POST request for getting the access token:{"error":"invalid_grant","message":"The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.","hint":"Failed to verify `code_verifier`."} I already checked the code_verifier and it's the same on both request ./authorization and ./token |
Aug 2, 2020 2:56 AM
#30
axiel7 said: I already checked the code_verifier and it's the same on both request ./authorization and ./token This is strange. Do you mind sharing your code? |
Aug 2, 2020 4:02 AM
#31
ZeroCrystal said: axiel7 said: I already checked the code_verifier and it's the same on both request ./authorization and ./token This is strange. Do you mind sharing your code? Sure I don't mind, this is my WIP GitHub repo: https://github.com/axiel7/MoeList The relevant parts are: LoginActivity LoginService PkceGenerator Edit: nvm, I wasn't logging correctly and the code_verifier wasn't the same |
axiel7Aug 2, 2020 7:22 AM
Aug 2, 2020 7:22 AM
#32
I don't have any practical experience with Kotlin, but I think that the cause is this (inside PkceGenerator.kt): @Throws(NoSuchAlgorithmException::class) fun generateChallenge(verifier: String): String { val bytes = verifier.toByteArray(StandardCharsets.US_ASCII) val md = MessageDigest.getInstance("SHA-256") md.update(bytes, 0, bytes.size) val digest = md.digest() return org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString(digest) } You're building the Code Challenge as a hashed version of the Code Verifier. This is correct for most services providing an OAuth authentication flow, but not for MAL. Quoting from the guide: MAL only allows the plain transformation for the Code Challenge. In other words, it means that you have to set the Code Challenge equal to the Code Verifier. Simple. Just remove everything related to the SHA hashing process and consider both the Code Verifier and the Code Challenge as the same string. Hopefully, the code will work as expected. EDIT: I posted this message 30 seconds after your edit. GG. |
Aug 6, 2020 8:45 AM
#33
I'm also having a problem with the auth ,but actually on the browser console the problem is that "require" is not defined I tried to convert the curl command to JS,but without success too var request = require('request'); var headers = { 'Authorization': 'Bearer 9aaa09ae343d953ea35061149e2e94e0' }; var dataString = 'status=completed&score=8'; var options = { url: 'https://api.myanimelist.net/v2/manga/2/my_list_status', method: 'PUT', headers: headers, body: dataString }; function callback(error, response, body) { if (!error && response.statusCode == 200) { console.log(body); } } request(options, callback); fetch("https://api.myanimelist.net/v2/anime?q=one&limit=4", { headers: { Authorization: "Bearer 9aaa09ae343d953ea35061149e2e94e0" } }) https://stackoverflow.com/questions/26274544/convert-command-curl-to-javascript/26274629 https://kigiri.github.io/fetch/ https://curl.trillworks.com/#node Can someone please help? |
Click here to see My Tampermonkey Scripts For MAL If you like my work, please consider supporting it! Cryptos / Patreon / Ko-Fi / BuyMeaCoffee https://cyber-sec0.github.io |
Aug 6, 2020 9:56 AM
#34
hacker09 said: I'm also having a problem with the auth ,but actually on the browser console the problem is that "require" is not defined require(...) is a Node.js function, you can't use it on a browser. Similarly, request is an npm package, and it doesn't seem like it offers a browser-compatible version. Plus, the package has been deprecated (see #3142), so you should avoid it if possible. You may want to use either the functions provided by vanilla JavaScript or rely on a third-party HTTP client to run your script on a web browser (assuming that you're not running the code on a Node.js server). |
Aug 6, 2020 7:03 PM
#35
@ZeroCrystal Thanks. Do you know if I can add my api key straight into the mal api url? I know how to do a js get api request using XMLHttpRequest, but I'm not sure if I can add header requests with that method. const Http = new XMLHttpRequest(); //Start the api call const url = https://myanimelist.net/v1/oauth2/MYKEYHERE/anime/17074/my_list_status; //Set the api url to be called Http.open("GET", url); //Set the get method to call the api url Http.send(); //Send the api request If I can't add my api key straight into the mal api url,can you please post how to do that request in JS only, that can work in the browser console? |
Click here to see My Tampermonkey Scripts For MAL If you like my work, please consider supporting it! Cryptos / Patreon / Ko-Fi / BuyMeaCoffee https://cyber-sec0.github.io |
Aug 7, 2020 6:12 AM
#36
hacker09 said: Do you know if I can add my api key straight into the mal api url? The access token and API client ID/secret can only be sent as part of the body of the HTTP requests. hacker09 said: If I can't add my api key straight into the mal api url,can you please post how to do that request in JS only, that can work in the browser console? As we've briefly discussed in the previous posts, at the moment it's not possible to interact with the API straight from the browser. Normally, you would write something like: function onComplete() { console.log(this.responseText); } const request = new XMLHttpRequest(); request.addEventListener("load", onComplete); request.open("GET", "https://api.myanimelist.net/v2/users/@me"); request.setRequestHeader("Authorization", "Bearer YOUR_ACCESS_TOKEN"); request.send(); // Use "request.send(JSON.stringify({ ... }))" when you need // to include parameters inside the body of the HTTP request. Unfortunately, the API servers don't include the CORS headers required to execute the above code snippet. If you don't know what CORS is, you can read this short MDN article. This is an issue that should be solved by MAL's dev team. In the meantime, the easiest solution is probably to use a public reverse proxy to access the API. CORS Anywhere is an example. You can replace the original URL with: function onComplete() { console.log(this.responseText); } const request = new XMLHttpRequest(); request.addEventListener("load", onComplete); request.open("GET", "https://cors-anywhere.herokuapp.com/api.myanimelist.net:443/v2/users/@me"); request.setRequestHeader("Authorization", "Bearer YOUR_ACCESS_TOKEN"); request.send(); This snippet should work as expected, but you are relying on a third-party service. It should be ok for testing, but you shouldn't be using it for public applications. Hosting your own reverse proxy is a better solution (the code for CORS Anywhere is open-source). Still, a proper solution has to be deployed by MAL. |
Aug 7, 2020 7:15 AM
#37
@ZeroCrystal Thank you so much again. I didn't know that Cross-origin resource sharing as abbreviated as CORS, I already had an idea about what it was, because I already had iframe problems because of this! This really sucks when an website blocks it ¬¬! haha Oh,so I will really need to wait the mal devs to fix that... I hope that I won't have problems, because I've already requested and got my api key, but I will need to wait the api to improve so I can use the api with tampermonkey. I hope that they don't "disable" my api key or do something else/bad with my mal account. Oh...so nice! I didn't know about https://cors-anywhere.herokuapp.com/ Can I also use this to iframe websites that blocks CORS? Yeah, it seems that CORS Anywhere might help me, but I agree with you, it's better to wait mal include the CORS headers required to execute these js codes. So you are suggesting me that I shouldn't rely on third-party services like CORS Anywhere, simply because they may "go down" and be unavailable at any time, or because they will probably block the ips of the people that use the tampermonkey script I did using their services, or because MAL has "legal" implications about it? (Like Mal states somewhere that it's not legal to use services like CORS Anywhere, because if I do I might have personal account/api problems) If I understood correctly I should change https://api.myanimelist.net/v2/users/@me with https://api.myanimelist.net/v2/users/@hacker09 right? How can I add the request parameters after the auth was done? function onComplete() { console.log(this.responseText); } const request = new XMLHttpRequest(); request.addEventListener("load", onComplete); request.open("GET", "https://cors-anywhere.herokuapp.com/api.myanimelist.net:443/v2/users/@me"); request.setRequestHeader("Authorization", "Bearer YOUR_ACCESS_TOKEN"); var dataString = 'status=completed&score=8'; var options = { url: 'https://api.myanimelist.net/v2/manga/2/my_list_status', method: 'PUT', headers: headers, body: dataString }; request.send('status=completed&score=8'); Your script returns the error {"error":"invalid_token"}, I tried using my Client Secret and Client ID in the place of '123' request.setRequestHeader("Authorization", "Bearer 123123123123123123123"); but all of them returned that error message. Do you know why? |
Click here to see My Tampermonkey Scripts For MAL If you like my work, please consider supporting it! Cryptos / Patreon / Ko-Fi / BuyMeaCoffee https://cyber-sec0.github.io |
Aug 7, 2020 8:33 AM
#38
hacker09 said: Can I also use this to iframe websites that blocks CORS? Maybe? It depends on your specific situation. hacker09 said: So you are suggesting me that I shouldn't rely on third-party services like CORS Anywhere, simply because they may "go down" and be unavailable at any time... I said that for a few reasons:
hacker09 said: If I understood correctly I should change https://api.myanimelist.net/v2/users/@me with https://api.myanimelist.net/v2/users/@hacker09 right? Nope, /@me is part of the URL, you must not change it. Take a look at the API documentation for more info. hacker09 said: Your script returns the error {"error":"invalid_token"}, I tried using my Client Secret and Client ID in the place of '123' request.setRequestHeader("Authorization", "Bearer 123123123123123123123"); but all of them returned that error message. Do you know why? All API functions require an Access Token. You need your Client ID and Client Secret to issue new Access Tokens linked to your application. Access Tokens are personal and identify a specific user. You should take a look at my guide to understand how to generate an Access Token. |
ZeroCrystalAug 7, 2020 8:36 AM
Aug 7, 2020 10:06 AM
#39
I see,so the only way possible to go get my api key is to do the steps 1-4 is and run that pyhton script. I will need to do that only 1 time right? Then to do step 4 and all the others, I will need to add more js codes to make always a POST request to https://myanimelist.net/v1/oauth2/token And I will probably need to add more codes to check when/if the user token is still valid or needs to be refreshed... Would be so much easier if the bearer auth key was just my client id for example... I hope that they change the way that the api key is generated... So the api call logic for any programming language is 1 First send every time a get request with the Header("Authorization", "Bearer YOUR_APIACCESS_TOKEN"); 2 Send every time a POST request to https://myanimelist.net/v1/oauth2/token to get the user token 3 Then always check if the key still valid or if needs to be refreshed 4 Finally add and send the parameters like this https://api.myanimelist.net/v2/manga/2/my_list_status 5 Finally get the api response, process and show the info somehow to the user Is that right? |
Click here to see My Tampermonkey Scripts For MAL If you like my work, please consider supporting it! Cryptos / Patreon / Ko-Fi / BuyMeaCoffee https://cyber-sec0.github.io |
Aug 7, 2020 10:44 AM
#40
hacker09 said: I see,so the only way possible to go get my api key is to do the steps 1-4 is and run that pyhton script. You don't necessarily need to run the Python script, I put it there as an example. Any combination of 128 characters is ok for the Code Verifier, you can generate it as you prefer. hacker09 said: So the api call logic for any programming language is 1 First send every time a get request with the Header("Authorization", "Bearer YOUR_APIACCESS_TOKEN"); 2 Send every time a POST request to https://myanimelist.net/v1/oauth2/token to get the user token 3 Then always check if the key still valid or if needs to be refreshed 4 Finally add and send the parameters like this https://api.myanimelist.net/v2/manga/2/my_list_status 5 Finally get the api response, process and show the info somehow to the user Is that right? There are approximately two different operations which you need to perform depending on the state of your programme:
|
Aug 7, 2020 11:14 AM
#41
If I don't need to generate the code verifier and code challenge for OAuth with PKCE frequently,then I'm fine. This tool is much easier and faster to use than any python script I guess https://tonyxu-io.github.io/pkce-generator/ Should I add my Client ID or my Client Secret to that tool? Let's suppose that this website returned the Code Challenge 123 and that the code verifier is 99999999999999999 To do the auth api request I would need to do this ???? function onComplete() { console.log(this.responseText); } const request = new XMLHttpRequest(); request.addEventListener("load", onComplete); request.open("GET", "https://cors-anywhere.herokuapp.com/api.myanimelist.net:443/v2/users/@me"); request.setRequestHeader("Authorization", "Bearer 12399999999999999999"); // Bearer Code_Challenge_code_verifier ???? request.send(); |
Click here to see My Tampermonkey Scripts For MAL If you like my work, please consider supporting it! Cryptos / Patreon / Ko-Fi / BuyMeaCoffee https://cyber-sec0.github.io |
Aug 7, 2020 1:14 PM
#42
hacker09 said: This tool is much easier and faster to use than any python script I guess https://tonyxu-io.github.io/pkce-generator/ Be careful with this kind of tools: they generally follow a different approach to generate the Code Verifier and Code Challenge. In the authorisation procedure implemented by MAL, the Code Verifier and Code Challenge must be the exact same string. Instead, the site you've linked generates a Code Challenge by hashing the Code Verifier, so they're different. You can simply press the Generate Code Verifier button and use it as both the Code Verifier AND the Code Challange. hacker09 said: Should I add my Client ID or my Client Secret to that tool? No, the Code Verifier doesn't depend on any external parameter. It's just a random string. hacker09 said: Let's suppose that this website returned the Code Challenge 123 and that the code verifier is 99999999999999999 To do the auth api request I would need to do this ???? function onComplete() { console.log(this.responseText); } const request = new XMLHttpRequest(); request.addEventListener("load", onComplete); request.open("GET", "https://cors-anywhere.herokuapp.com/api.myanimelist.net:443/v2/users/@me"); request.setRequestHeader("Authorization", "Bearer 12399999999999999999"); // Bearer Code_Challenge_code_verifier ???? request.send(); You're skipping too many steps. The Authorization header requires an Access Token, and not the Code Verifier or your Client ID. The /v2/users/@me endpoint is just an example of a possible API function which you can call AFTER you've obtained an Access Token. To issue an Access Token you have to follow the steps 2-4 of the guide. They use different URLs, and they don't require the Authorization header as you still don't have an Access Token which you can use. For example, you can use the following code to convert the Authorisation Code obtained from step 2 into an Access Token: function onComplete() { console.log(this.responseText); } const encodeParameters = p => Object.entries(p).map(kv => kv.map(encodeURIComponent).join("=")).join("&"); const request = new XMLHttpRequest(); request.addEventListener("load", onComplete); request.open("POST", "https://cors-anywhere.herokuapp.com/myanimelist.net:443/v1/oauth2/token"); request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); request.send(encodeParameters({ client_id: "CLIENT ID", client_secret: "CLIENT SECRET", code: "AUTHORISATION CODE", code_verifier: "CODE VERIFIER", grant_type: "authorization_code" })); Check the guide to see which URLs and parameters are required for each step. |
Aug 7, 2020 4:05 PM
#43
@ZeroCrystal Thanks for your help,now this makes more sense. 1The Generate Code Verifier button didn't work on step 2, so I clicked on "Generate Code Challenge" and copied that codes They will be like 47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU The next step is 2 Make my own URL, to be opened later My Own URL Example that worked for me https://myanimelist.net/v1/oauth2/authorize?response_type=code&client_id=99999&code_challenge=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU Then I was redirected to https://greasyfork.org/en?code=111111111 In the place of 111 I got my authorization code with random numbers and letters, it had a total of 808 characters. 3 I opened the Url I just built on step 2 on the browser console and I pressed "Allow". Then I was redirected to another website,the website will be like www.website.com/?code=111111111 I copied everything that was after ?code= This will be my authorization code right? 4 Run function onComplete() //Don't change anything on this line! { console.log(this.responseText); //Don't change anything on this line! } //Don't change anything on this line! const encodeParameters = p => Object.entries(p).map(kv => kv.map(encodeURIComponent).join("=")).join("&"); //Don't change anything on this line! const request = new XMLHttpRequest(); //Don't change anything on this line! request.addEventListener("load", onComplete); //Don't change anything on this line! request.open("POST", "https://cors-anywhere.herokuapp.com/myanimelist.net:443/v1/oauth2/token"); //Don't change anything on this line! request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); //Don't change anything on this line! request.send(encodeParameters({ client_id: "CLIENT_ID", client_secret: "CLIENT_SECRET", code: "AUTHORIZATION_CODE", //This needs to be replaced.You will get this on step 2 code_verifier: "CODE_VERIFIER", //Paste the Generated Code Verifier numbers in the place of "CODE VERIFIER" grant_type: "authorization_code" //Don't change anything on this line! })); //Don't change anything on this line! What's the Parameter code_verifier: the Code Verifier generated in Step 2. (REQUIRED)?? I tried adding the same thing on CODE_VERIFIER and AUTHORIZATION_CODE , but I got this error {"error":"invalid_grant","message":"The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.","hint":"Failed to verify `code_verifier`."} |
hacker09Nov 9, 2020 4:50 AM
Click here to see My Tampermonkey Scripts For MAL If you like my work, please consider supporting it! Cryptos / Patreon / Ko-Fi / BuyMeaCoffee https://cyber-sec0.github.io |
Aug 8, 2020 8:10 AM
#44
hacker09 said: 1The Generate Code Verifier button didn't work on step 2, so I clicked on "Generate Code Challenge" and copied that codes Weird, that button only runs a trivial JS script: function generateCodeVerifier() { var code_verifier = generateRandomString(128); document.getElementById("code_verifier").value = code_verifier; } function generateRandomString(length) { var text = ""; var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"; for (var i = 0; i < length; i++) { text += possible.charAt(Math.floor(Math.random() * possible.length)); } return text; } hacker09 said: This will be my authorization code right? Yep. However, when I tested it, the Authorisation Code was 978 characters long. I don't know if you missed part of the string, or it simply has a variable length. hacker09 said: What's the Parameter code_verifier: the Code Verifier generated in Step 2. (REQUIRED)?? Yes. The Code Verifier/Code Challange is the same string you've generated at the beginning of the process. hacker09 said: I tried adding the same thing on CODE_VERIFIER and AUTHORIZATION_CODE , but I got this error {"error":"invalid_grant","message":"The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.","hint":"Failed to verify `code_verifier`."} Strange, try again from the beginning and double-check that you didn't accidentally put any whitespace at the start or end of the string. I have another tip for you: since you're developing a userscript and the code is publically accessible, you should change the app type of your application in the API panel. The "web" app type should be chosen by people who are developing a website or a web service where they can hide their Client Secret from the user. In your case, the Client Secret is available to anyone who's using your script. I suggest you create a new application with an App Type set to "other". This is recommended for public scripts like yours, as it doesn't receive a Client Secret. It works in the exact same way as a "web" application, except that you don't need to provide a Client Secret to issue a new Access Token or to refresh an existing one. |
Aug 13, 2020 4:29 AM
#45
@ZeroCrystal It does have a variable length.I tried generating it another time to see if I was doing something wrong,and in the 2 time I generated that code the code had something like 750 or 850 characters,the code changed a bit but changed. The Code Verifier/Code Challange is the same string you've generated at the beginning of the process. Okay so that's the huge code I get on the url...But why I got an error then? I surely didn't accidentally put any whitespace at the start or end of the string. Yeah I was wondering about that... Having a secret and private client secret code is dumb if I need to add that codes to an userscript hahha. I also thought about doing what you said, but then I will have problems right? Like I need to explain to someone to erase my old api, because I won't use that one. Or at least I will have -1 possibility of making another userscript/website/program for example. Everyone is limited to 3 keys only, so I guess that it means that every user on mal can only make 3 userscripts or websites or programs. 3 is a really low number I think,I hope they change that in the future too. I will try doing the steps again, I will probably need to download python to run that python script |
Click here to see My Tampermonkey Scripts For MAL If you like my work, please consider supporting it! Cryptos / Patreon / Ko-Fi / BuyMeaCoffee https://cyber-sec0.github.io |
Aug 13, 2020 5:49 AM
#46
hacker09 said: But why I got an error then? I'm not sure. I tried generating a new Access Token using the JS scripts I put in my previous messages, and it worked swiftly. You should test it again using a different programming language or sending the requests with a fancy HTTP client like Insomnia Core or Postman. If it works using a different medium, then there must be a problem with your code. hacker09 said: I also thought about doing what you said, but then I will have problems right? Like I need to explain to someone to erase my old api, because I won't use that one. You don't have to give any special explanation, and you won't get in troubles. The API is still in open beta, so this kind of changes won't cause problems. You can easily delete your existing application from the API panel by clicking Edit → Delete (at the bottom of the page). The deletion process is immediate. Also, you don't need to create multiple applications for multiple userscripts. You only need one, so you can share the same Client ID among all your userscripts. hacker09 said: I will try doing the steps again, I will probably need to download python to run that python script The Python script I put in the guide is just an example of how you can generate a random Code Verifier / Code Challenge, you don't have to run it. For testing purpose, you can simply use a 128 characters-long string containing the same character (e.g. 'A' × 128 times, you can copy-paste it from here). |
Aug 17, 2020 4:14 PM
#47
@ZeroCrystal Ok.I'm also using that js codes. ok, I will delete my actual api then. wow, can I really use that? hahahaa A bunch of AAAAAAAAAAAA?? https://gitlab.com/-/snippets/2004250/raw I thought that these auth codes couldn't be used more than once, for more than 1 person. |
hacker09Aug 17, 2020 4:18 PM
Click here to see My Tampermonkey Scripts For MAL If you like my work, please consider supporting it! Cryptos / Patreon / Ko-Fi / BuyMeaCoffee https://cyber-sec0.github.io |
Aug 23, 2020 5:34 AM
#48
I'm a bit confused about how the new API can be used in my specific use-case. I'm the developer of the MyAnimeList Plex Metadata Agent and I don't really have access to a Browser there, at least not from the Agent itself. The only thing that is "user-driven" is that they could select some different settings for the agent like "how many images should be downloaded" or "at what resolution". Anything else happens without the interaction of the user. There might be a way to expose an URL in those settings as some form of "dummy" settings which includes the URL but that is not accessible by the script so any URL generation as stated in "Step 2" wouldn't be possible and that would prevent the User to go to the authorisation page and give the Agent permission to access the API. Which would mean that I would have to create a whole server-side infrastructure that is also "secure" and GDPR compliant which stores the authorization code that then the user somehow accesses from the Agent. I mean, I'm glad that the API is using a more secure way of handling API request but doesn't this ignore everyone who would want to do requests without a GUI? Or am I missing something here? |
Aug 23, 2020 7:33 AM
#49
Fribbtastic said: I mean, I'm glad that the API is using a more secure way of handling API request but doesn't this ignore everyone who would want to do requests without a GUI? Or am I missing something here? Unfortunately, it's not possible to obtain an Access Token in a completely automated way at the moment. It would be nice to be able to generate a private and static Access Key directly from your MAL account panel, but I doubt that something like this could be implemented in a short time. The simplest workaround I can think of would be to add a new text box to the settings screen of your agent where to insert the user's Authorisation Code. Somewhere near the text box, you can put a clickable URL or a button redirecting the user to a static webpage where you can perform the authorisation procedure. You can build your web application as a public OAuth client (i.e. a client which doesn't use a Client Secret): in this way, you don't need any kind of complex backend as you wouldn't be storing any personal information about your users. Simply, let them be redirected to the MAL authorisation page; once they approve the request, they are redirected back to your website where you can use a little bit of JavaScript to display the code (obtained from the URL's query string) that they have to copy-paste inside the settings panel of your Plex agent. In this way, you can use any of the thousands of free static hosting providers available on the web (or you can use your personal website if you have one). Once you have the Authorisation Code, you can easily issue a new Access and Refresh Tokens and store them locally. You can create a public OAuth client by selecting any option different from "web" as the App Type of your MAL API application (in this case, "other" would be the best choice). |
Aug 23, 2020 7:48 AM
#50
ZeroCrystal said: Fribbtastic said: I mean, I'm glad that the API is using a more secure way of handling API request but doesn't this ignore everyone who would want to do requests without a GUI? Or am I missing something here? Unfortunately, it's not possible to obtain an Access Token in a completely automated way at the moment. It would be nice to be able to generate a private and static Access Key directly from your MAL account panel, but I doubt that something like this could be implemented in a short time. The simplest workaround I can think of would be to add a new text box to the settings screen of your agent where to insert the user's Authorisation Code. Somewhere near the text box, you can put a clickable URL or a button redirecting the user to a static webpage where you can perform the authorisation procedure. You can build your web application as a public OAuth client (i.e. a client which doesn't use a Client Secret): in this way, you don't need any kind of complex backend as you wouldn't be storing any personal information about your users. Simply, let them be redirected to the MAL authorisation page; once they approve the request, they are redirected back to your website where you can use a little bit of JavaScript to display the code (obtained from the URL's query string) that they have to copy-paste inside the settings panel of your Plex agent. In this way, you can use any of the thousands of free static hosting providers available on the web (or you can use your personal website if you have one). Once you have the Authorisation Code, you can easily issue a new Access and Refresh Tokens and store them locally. You can create a public OAuth client by selecting any option different from "web" as the App Type of your MAL API application (in this case, "other" would be the best choice). That is actually a good idea to do that with a small website that just retrieves the authorisation code through JavaScript which is also just client-side. I would have to look into how I can integrate this in the settings page because this is just defined through a formatted text file which is then loaded by Plex to read the settings, but even if that doesn't work this would then just be another step in the "setup" or installation process. I had already created a client ID and everything and when I first played around with it I was just authenticating with the username and password that the user then could enter in the agent settings but this doesn't seem to be allowed anymore, which is good for security reasons but this adds another step in this process which is a bit tedious. But thanks that gave me something to start. |
More topics from this board
» Requesting additional authorizationsSomeNewGuy - Aug 18 |
1 |
by ZeroCrystal
»»
Aug 22, 8:31 AM |
|
» Scraping from HTML suggested rateDavenzo - Jan 8, 2023 |
4 |
by 7k72
»»
Jun 23, 6:35 AM |
|
» Accessing Many Users' Listloukylor - Jun 11 |
0 |
by loukylor
»»
Jun 11, 3:07 PM |
|
» Caching strategy to avoid making additional API callsJakuten - Jun 3 |
4 |
by Jakuten
»»
Jun 8, 11:30 AM |
|
» Manga Update API Endpoint Disabledarturitojedi - May 15 |
0 |
by arturitojedi
»»
May 15, 6:45 PM |