Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting 400 after login with Npsso: Client does not have grant type sso_cookie #166

Closed
felzend opened this issue Feb 11, 2021 · 42 comments
Closed
Labels

Comments

@felzend
Copy link

felzend commented Feb 11, 2021

$psn_client = new Client(); $psn_client->loginWithNpsso('MY TOKEN');

{"error":"unauthorized_client","error_description":"Client does not have grant type: [\"sso_cookie\"]","docs":"https://auth.api.sonyentertainmentnetwork.com/docs/","error_code":4151}

Client error: POST https://auth.api.sonyentertainmentnetwork.com/2.0/oauth/token` resulted in a 400 Bad Request response: {"error":"unauthorized_client","error_description":"Client does not have grant type: ["sso_cookie"]","docs":"https://a (truncated...)`

Fatal error: Uncaught GuzzleHttp\Exception\ClientException: Client error: POST https://auth.api.sonyentertainmentnetwork.com/2.0/oauth/token` resulted in a 400 Bad Request response: {"error":"unauthorized_client","error_description":"Client does not have grant type: ["sso_cookie"]","docs":"https://a (truncated...) in C:\xampp\htdocs\psn\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php:113 Stack trace: #0 C:\xampp\htdocs\psn\vendor\guzzlehttp\guzzle\src\Middleware.php(65): GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Psr7\Response)) #1 C:\xampp\htdocs\psn\vendor\guzzlehttp\promises\src\FulfilledPromise.php(41): GuzzleHttp\Middleware::GuzzleHttp{closure}(Object(GuzzleHttp\Psr7\Response)) #2 C:\xampp\htdocs\psn\vendor\guzzlehttp\promises\src\TaskQueue.php(48): GuzzleHttp\Promise\FulfilledPromise::GuzzleHttp\Promise{closure}() #3 C:\xampp\htdocs\psn\vendor\guzzlehttp\promises\src\Promise.php(248): GuzzleHttp\Promise\TaskQueue->run(true) #4 C:\xampp\htdocs\ in C:\xampp\htdocs\psn\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php on line 113`

@Argosth
Copy link

Argosth commented Feb 12, 2021

Same here, I thought was a banned IP, but for that case is error 403, not 400, I hope someone can told us something.

@joekw
Copy link

joekw commented Feb 12, 2021

I'm seeing this too and suspect they've disabled the old 2.0 API.

EDIT: Done some more testing and the old API endpoints still work so I'm assuming it's just the 2.0 method of authentication that they've disabled?

@felzend
Copy link
Author

felzend commented Feb 12, 2021

I'm seeing this too and suspect they've disabled the old 2.0 API.

EDIT: Done some more testing and the old API endpoints still work so I'm assuming it's just the 2.0 method of authentication that they've disabled?

Interesting. Thanks.

In which version are those old API endpoints?

@that1estonian
Copy link

Same problem 😞

@pacMakaveli
Copy link

This method works for me. Sorry I can't help with this repo but by PHP skills are long gone and I'm not familiar with this codebase. If you need some more help give me a shout and I'd be more than happy to help.

https://github.com/games-directory/api-psn/blob/master/lib/play_station_network_api/session.rb

PlayStationNetworkAPI::Session.new('npsso').authenticate

@isFakeAccount
Copy link

Son of a b.....

@kris-dev-cloudwarelab
Copy link

Facing the same issue right now

Looking through Network logs on Chrome/Firefox seems that the old 2.0/auth/token endpoint is still used by PSN, but instead of returning the access token and refresh token, its redirected to the new ca.account.sony.com endpoints, which then execute further

A comperhensive fix would be much appreciated @pacMakaveli code example is a great starting point, but it seems that it uses some /authz/v3 endpoint which is not being used by the PSN website - is it an endpoint for the app/console?

My main concern is how to obtain a refresh token. Getting the access token is easy by just logging in and finding the Bearer, but a refresh token under the current scheme seems either hidden or depreciated

@pacMakaveli
Copy link

@kris-dev-cloudwarelab , yes, that endpoint is now used by the new app.
I just added a new comment: https://github.com/games-directory/api-psn/issues/1 with how to obtain the NPSSO which will then give you the refresh_token , along with the access_token for the Bearer authorization.
Let me know if I can help any further, here, or there.

@Alex314Ru
Copy link

@pacMakaveli Thank you for the example! But where did you get the Authorization header for the /authz/v3/oauth/token request? Is it safe that you share it/to use it?

@pacMakaveli
Copy link

@Alex314Ru

        headers: {
          'Authorization' => 'Basic YWM4ZDE2MWEtZDk2Ni00NzI4LWIwZWEtZmZlYzIyZjY5ZWRjOkRFaXhFcVhYQ2RYZHdqMHY='
        },

I don't know about safe, to be honest. After all, the API is not a public resource. I got this by reverse-engineering the PlayStation apk and it's being used by the app.

@kris-dev-cloudwarelab
Copy link

kris-dev-cloudwarelab commented Feb 18, 2021

@pacMakaveli
Lifesaver - I have implemented your app endpoint approach on Node-RED finally and received the access_token and refresh_token

For those who are still struggling, a few of my learnings from @pacMakaveli code and solution

  1. The /oauth/v3/authorize endpoint needs the npsso AND ALSO Authorization headers basic token thats provided by @pacMakaveli
    Also note that this endpoint will try to redirect you "to the app", however if you are using a node.js server to make the requests it will of course say the redirect "URL" is jibbrish. So make sure you disable redirects as is done in the Ruby code. And then look at the header.location where it tries to redirect you - that holds the code and cid (client_id?)

  2. The /oauth/v3/token endpoint again needs the Authorization header with the basic token and the code from /v3/authorize

So these two requests let you go from an npsso you scrape out of your manual login and arrive at a pair of access and refresh tokens which preserve access for 1h for access token and 2 months for the refresh token (which can create new access tokens for you). Or they will both become redundant when PSN does another update..

After a few hours it seems pretty clear, however I would never find those endpoints without the help of @pacMakaveli

For those whom this might help, here are the two key pieces of first-draft-code in node.js that works for me. These are written for Node-RED though, so its a bit different, but should illustrate the key points

Accessing /authorize

let npsso = msg.payload.npsso;

msg.api_params = {
    AUTH_API: 'https://ca.account.sony.com/api/authz/v3/oauth/authorize',
    CLIENT_ID: 'ac8d161a-d966-4728-b0ea-ffec22f69edc',
    SCOPE: 'psn:clientapp psn:mobile.v1'
};

msg.payload = {
    'client_id': msg.api_params.CLIENT_ID,
          'access_type': 'offline',
          'redirect_uri': 'com.playstation.PlayStationApp://redirect',
          'response_type': 'code',
          'scope': msg.api_params.SCOPE
};

msg.cookies = {
    'npsso': npsso
};


msg.headers = {
    "Content-Type": "application/x-www-form-urlencoded",
    "Host": "ca.account.sony.com",
"Referer":  "https://my.playstation.com/",
"Authorize": "Basic YWM4ZDE2MWEtZDk2Ni00NzI4LWIwZWEtZmZlYzIyZjY5ZWRjOkRFaXhFcVhYQ2RYZHdqMHY="
};

let q = "?access_type=offline";
q += "&scope=psn:clientapp psn:mobile.v1";
q += "&client_id=" + msg.api_params.CLIENT_ID;
q += "&redirect_uri=com.playstation.PlayStationApp://redirect"; //com.playstation.PlayStationApp://redirect";
q += "&response_type=code";
msg.url = msg.api_params.AUTH_API + encodeURI(q); 
msg.method = "GET";
msg.followRedirects = false;
return msg;

Accessing /token

let location = msg.headers.location;
let code = location.match(/code=([A-Za-z0-9:\?_\-\.\/=]+)/)[1];
let cid = location.match(/cid=([A-Za-z0-9:\?_\-\.\/=]+)/)[1];

msg.payload = {
    'scope': msg.api_params.SCOPE,
  'code': code,
  'grant_type': 'authorization_code',
  'redirect_uri': 'com.playstation.PlayStationApp://redirect',
  'token_format': 'jwt'
};

msg.headers = {
  'Authorization': 'Basic YWM4ZDE2MWEtZDk2Ni00NzI4LWIwZWEtZmZlYzIyZjY5ZWRjOkRFaXhFcVhYQ2RYZHdqMHY=',
  'Content-Type': "application/x-www-form-urlencoded"
};
delete msg.cookies;
msg.method = "POST";
msg.url = "https://ca.account.sony.com/api/authz/v3/oauth/token";
msg.followRedirects = true;
delete msg.statusCode;
return msg;

@pacMakaveli
Copy link

pacMakaveli commented Feb 18, 2021

Awesome to hear that! Great job with the detailed description as well.
As for the cid , I can't remember why I even extracted it to be honest. Haven't found a use case for it so far.

For anyone still struggling, this is my Postman Workspace : https://app.getpostman.com/join-team?invite_code=86c018d31448e533a0ea3f3314f7857b where I test the endpoints.
If I have some time next week I'll organise it nicely with all the available endpoints so you're not constricted with Ruby, PHP or Javascript syntax.

@Tustin
Copy link
Owner

Tustin commented Feb 18, 2021

Thanks guys -- I'll see if I can update the current version of the library to use the new auth method. I'm still (slowly) working on the new version but I just haven't had much time recently to focus on it. Hopefully I can finish it up soon so we can have the new API all setup when Sony inevitably deprecates the old API.

@felzend
Copy link
Author

felzend commented Feb 23, 2021

Guys, I still didn't figure out how to get the Refresh Token after inputing my NPSSO Token.

I tried those examples above using Javascript & Ruby but didn't find a way to make it work.

May you give me a example, please?

@pacMakaveli
Copy link

I think @kris-dev-cloudwarelab example is very good. Is there an error you get or..? Take us through your process

@felzend
Copy link
Author

felzend commented Feb 23, 2021

@pacMakaveli I sent you an email with a doubt about your Ruby gem, which I'll convert to PHP, but that only worked on Ruby for while (one of the requests).

I tried @kris-dev-cloudwarelab 's example in Postman. Once it works I'll convert to PHP, also..

Here's my example using Postman:

https://www.getpostman.com/collections/31771518d73338dbafc4

Basically the error is this one:

image

@pacMakaveli
Copy link

You're trying to GET a request. Change the GET to POST and it should work.

@felzend
Copy link
Author

felzend commented Feb 23, 2021

Inside your gem and on his example that should be a GET.

image

@pacMakaveli
Copy link

Sorry, I was looking at the body you were trying to pass and assumed you were trying to POST.
So, first of all, you can't pass a body to a GET request, body is only for POST. For get you need to pass params.

Here's the Postman process.
To get the code:
image
Headers
image
Settings
image

It's very important you disable Automatically follow redirects in Settings.

The in the response headers of the request, you should see this:

image

And the to get the account access token and what not:
image
Header
image

@JardaPazdy
Copy link

Hello,
using same way I started to receiving forbidden this morning :-/

403 Forbidden` response: <TITLE>Access Denied</TITLE>

Access Denied

You don't have permission to access

Anyone else same problem?
Thanks

@Strategeru
Copy link

Strategeru commented Feb 27, 2021

403 Forbidden` response: <TITLE>Access Denied</TITLE>

403 means your IP is banned for API Requests / Akamai.

@JardaPazdy
Copy link

JardaPazdy commented Feb 28, 2021

Yes I found it too :( Probably too much request at short time ... I have to use proxy server now, and it works. Hope ban is only temporary.

@jobsfan
Copy link

jobsfan commented Mar 11, 2021

@pacMakaveli I sent you an email with a doubt about your Ruby gem, which I'll convert to PHP, but that only worked on Ruby for while (one of the requests).

I tried @kris-dev-cloudwarelab 's example in Postman. Once it works I'll convert to PHP, also..

Here's my example using Postman:

https://www.getpostman.com/collections/31771518d73338dbafc4

Basically the error is this one:

image

hello there, have you finished to convert it into PHP?

according to @pacMakaveli 's postman method, I do can get the accesstoken and refreshtoken. However the refreshtoken can not be used in @Tustin 's php lib.

1111

I guess the refreshtoken must match the related client-id stuff. It can not be used in the php version lib.
If you convert ruby api to php one, can you help me with this?

@that1estonian
Copy link

Any updates on this?

@pacMakaveli
Copy link

My app still works fine with the API. If I had to guess, I think @jobsfan is running my method against the old version of the API in this repo.
Make sure you're running against the master branch because the JWT token you get from the new authentication endpoint doesn't work with the old API.

@that1estonian
Copy link

that1estonian commented Mar 15, 2021

Yea... I'm not very good at this, so I'm waiting for an update 😄

EDIT: Also, when i update to dev-master, I get a following error: Uncaught Error: Class 'PlayStation\Client' not found

@Tustin
Copy link
Owner

Tustin commented Mar 15, 2021

Yea... I'm not very good at this, so I'm waiting for an update 😄

EDIT: Also, when i update to dev-master, I get a following error: Uncaught Error: Class 'PlayStation\Client' not found

Sorry, master branch wasn't quite ready yet so there's a ton of breaking changes that will require you to change some of your code a bit. I wasn't expecting Sony to kill the old API so quickly so I haven't really been focusing on finishing the new API code.

@Tustin
Copy link
Owner

Tustin commented Mar 15, 2021

I've updated the README to show a notice about the current state of the library. I will be working on this during the week to try to get all the bugs ironed out so we can have a working version again 😄

@that1estonian
Copy link

@Tustin thank you :)

@pradella
Copy link

pradella commented Mar 25, 2021

Awesome to hear that! Great job with the detailed description as well.
As for the cid , I can't remember why I even extracted it to be honest. Haven't found a use case for it so far.

For anyone still struggling, this is my Postman Workspace : https://app.getpostman.com/join-team?invite_code=86c018d31448e533a0ea3f3314f7857b where I test the endpoints.
If I have some time next week I'll organise it nicely with all the available endpoints so you're not constricted with Ruby, PHP or Javascript syntax.

Can you please send an updated link for this Postman Workspace? Struggling to learn the new API (just found this repo).
Appreciate your help

EDIT: nevermind, found in another answer, thanks a lot

@Reuns
Copy link

Reuns commented Mar 30, 2021

I also have this issue since this afternoon.
But I don't know how to code ... actually, just a bit of PHP so I don't understand any of your solution.
Let's hope the new version will be available soon :/

@that1estonian
Copy link

Sorry, I was looking at the body you were trying to pass and assumed you were trying to POST.
So, first of all, you can't pass a body to a GET request, body is only for POST. For get you need to pass params.

Here's the Postman process.
To get the code:
image
Headers
image
Settings
image

It's very important you disable Automatically follow redirects in Settings.

The in the response headers of the request, you should see this:

image

And the to get the account access token and what not:
image
Header
image

I'm trying to follow this, but getting "Mandatory parameter 'grant_type' is missing"

const step2 = await axios.post(`${variables.AUTH_API}/token`, {
                data: {
                    grant_type: 'authorization_code',
                    client_id: variables.CLIENT_ID,
                    response_type: 'code',
                    code: code,
                    scope: variables.SCOPE,
                    redirect_uri: variables.REDIRECT_URI,
                    token_format: 'jwt'
                },
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                    'Authorization': 'Basic YWM4ZDE2MWEtZDk2Ni00NzI4LWIwZWEtZmZlYzIyZjY5ZWRjOkRFaXhFcVhYQ2RYZHdqMHY='
                }
            });

@pacMakaveli
Copy link

pacMakaveli commented Apr 6, 2021

I'm trying to follow this, but getting "Mandatory parameter 'grant_type' is missing"

const step2 = await axios.post(`${variables.AUTH_API}/token`, {
                data: {
                    grant_type: 'authorization_code',
                    client_id: variables.CLIENT_ID,
                    response_type: 'code',
                    code: code,
                    scope: variables.SCOPE,
                    redirect_uri: variables.REDIRECT_URI,
                    token_format: 'jwt'
                },
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                    'Authorization': 'Basic YWM4ZDE2MWEtZDk2Ni00NzI4LWIwZWEtZmZlYzIyZjY5ZWRjOkRFaXhFcVhYQ2RYZHdqMHY='
                }
            });

You'd get that error if your headers or body are not passed correctly.

let axios = require('axios');
let qs = require('qs');
let data = qs.stringify({
  'redirect_uri': 'com.playstation.PlayStationApp://redirect',
  'scope': 'psn:clientapp psn:mobile.v1',
  'token_format': 'jwt' 
});
let code = code;
let config = {
  method: 'post',
  url: `https://ca.account.sony.com/api/authz/v3/oauth/token?code=${ code }&grant_type=authorization_code&redirect_uri=com.playstation.PlayStationApp://redirect`,
  headers: { 
    'Host': 'ca.account.sony.com', 
    'Referer': 'https://my.playstation.com/', 
    'Authorization': 'Basic YWM4ZDE2MWEtZDk2Ni00NzI4LWIwZWEtZmZlYzIyZjY5ZWRjOkRFaXhFcVhYQ2RYZHdqMHY=', 
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  data : data
};

axios(config).then(function (response) {
  console.log(JSON.stringify(response.data));
}).catch(function (error) {
  console.log(error);
});

Try this, if it works, it means axios is not sending the headers or body correctly.

@that1estonian
Copy link

that1estonian commented Apr 6, 2021

@pacMakaveli same error 🙄

data: {
      error: 'invalid_request',
      error_description: "Mandatory parameter 'grant_type' is missing",
      error_code: 4098,
      error_uri: 'https://auth.api.sonyentertainmentnetwork.com/openapi/docs'
}

did that work for u tho?

@that1estonian
Copy link

@pacMakaveli sorry for spamming u 😆

anyways, your XMLHttpRequest example worked, so i'm doing something wrong with axios or it just won't work for this

@that1estonian
Copy link

ok, so i got it to work with got. just dropping it here, incase anyone curios

async getTokens (npsso) {
        try {
            const step1 = await got.get(`${variables.AUTH_API}/authorize?access_type=offline&client_id=${variables.CLIENT_ID}&redirect_uri=${variables.REDIRECT_URI}&response_type=code&scope=${variables.SCOPE}`, {
                followRedirect: false,
                headers: {
                    'Cookie': 'npsso=' + npsso
                },
                responseType: 'json'
            });

            const location = step1.headers.location;

            const code = location.match(/code=([A-Za-z0-9:\?_\-\.\/=]+)/)[1];

            const step2 = await got.post(`${variables.AUTH_API}/token?code=${code}&grant_type=authorization_code&redirect_uri=${variables.REDIRECT_URI}`, {
                withCredentials: true,
                headers: {
                    'Host': 'ca.account.sony.com',
                    'Referer': 'https://my.playstation.com/',
                    'Authorization': 'Basic YWM4ZDE2MWEtZDk2Ni00NzI4LWIwZWEtZmZlYzIyZjY5ZWRjOkRFaXhFcVhYQ2RYZHdqMHY=',
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                body: `code=${code}&grant_type=authorization_code&redirect_uri=${variables.REDIRECT_URI}&scope=${variables.SCOPE}&token_format=jwt`,
                responseType: 'json'
            });

            return {
                'accessToken': step2.body['access_token'],
                'refreshToken': step2.body['refresh_token']
            };
        } catch (error) {
            throw new Error(error);
        };
};

@that1estonian
Copy link

@pacMakaveli hey, i saw u took down your psn repo. do u still have the api endpoints somewhere? 🙄

@pacMakaveli
Copy link

@pacMakaveli hey, i saw u took down your psn repo. do u still have the api endpoints somewhere? 🙄

I sure do! I think pretty much everything is still on postman, but I'll share them here later as well.

Sorry, I had to make it private for personal reasons. I hope I can make them public again soon.

@that1estonian
Copy link

waiting

@stale
Copy link

stale bot commented Jun 21, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Jun 21, 2021
@stale stale bot closed this as completed Jun 29, 2021
@amirm8170
Copy link

@pacMakaveli hello ,
I should talk to you in private . how we can do that ?
I want to ask some questions....
thanks

@pacMakaveli
Copy link

@amirm8170 vlad [at] games [dot] directory

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests