Debugging Sonos error after refresh response - sonos

The Sonos Music API (SMAPI) implementation I built is working fine. I can select playlists/albums and play tracks using customsd.html. But after a couple of minutes the Sonos app fails and tells me "Trial period expired" (Sonos's Client.LoginUnauthorized error message).
I keep an error log which keeps track of all Sonos request on the server. In it, you can see that at 21:39:54 a refresh token (Client.TokenRefreshRequired) is sent back and the subsequent request uses this authentication token to authorize the getLastUpdate request.
The next request fails because it uses an invalidated authorization token.
2018-12-15 21:39:19.680877: server gets request: getMediaURI
2018-12-15 21:39:19.681059: user agent: ["Linux UPnP\/1.0 Sonos\/47.2-59120 (ZP90)"]
2018-12-15 21:39:19.767269: AUTHORIZE REQUEST starting with token: 26052eec7baed95cf51bb497acb74445e7f3f86c
2018-12-15 21:39:20.022666: Successfully ended getMediaURI
2018-12-15 21:39:54.861666: server gets request: getLastUpdate
2018-12-15 21:39:54.861842: user agent: ["Linux UPnP\/1.0 Sonos\/47.2-59120 (WDCR:Microsoft Windows NT 10.0.17134)"]
2018-12-15 21:39:54.953047: AUTHORIZE REQUEST starting: with token: 26052eec7baed95cf51bb497acb74445e7f3f86c
2018-12-15 21:39:55.177064: Sending refreshed access token. token 93467644b3c00ec738a06f41abb44f5925977da6
2018-12-15 21:39:55.997627: server gets request: getLastUpdate
2018-12-15 21:39:55.998382: user agent: ["Linux UPnP\/1.0 Sonos\/47.2-59120 (WDCR:Microsoft Windows NT 10.0.17134)"]
2018-12-15 21:39:56.111795: AUTHORIZE REQUEST starting with token: 93467644b3c00ec738a06f41abb44f5925977da6
2018-12-15 21:39:56.338871: Successfully ended getLastUpdate
2018-12-15 21:40:10.834301: server gets request: getMediaURI
2018-12-15 21:40:10.834675: user agent: Linux UPnP\/1.0 Sonos\/47.2-59120 (ZP90)
2018-12-15 21:40:10.928440: AUTHORIZE REQUEST starting with token: 26052eec7baed95cf51bb497acb74445e7f3f86c
2018-12-15 21:40:10.940039: FAILED AUTHENTICATION
The authentication fails when called at 21:40:10. This call is made by user agent ending with (ZP90), which I presume is my physical Sonos player. The refreshed acces token is sent to the user agent ending with (WDCR:Microsoft Windows NT 10.0.17134); presumably my desktop Sonos app?.
Is it normal that two different user agents call the service? if so, how to deal with expiring authorization tokens? Should there be a delay in expiring them? if so, how long should this delay be?
EDIT:
My flow is:
A request is sent with token A by the Controller.
My authorization server says it has expired, revokes token A and sends back the new token B.
The Controller sends requests with token B, all fine!
Next thing that happens: the Player sends a request with token A, which has been revoked, so we are forced to send back an unauthorized token error.
The process gets stuck because the Player keeps requesting with token A. Error! We cannot refresh a revoked token!
How could I continue with revoked authorization tokens?

The player executes its own token refresh flow. As long as you correctly handle the refresh flow on your end, things will work out. If you notice an expired token, simply refresh it, regardless of client.
As an aside, if the player does get a refresh token, it will pass it up to the controller. The opposite does not happen (as you noticed).

Related

How to get access token using oauth 2.0 authorization grant type in rest assured

I have an api with oauth2.0 authorization grant type authentication which has the following steps -
Get method for authorization code which opens up a form in browser where you need to enter credentials. This results in a series of post redirect requests and finally returns a authorization code in third post response header
Now a post request is sent, with grant type authorization code containing client credentials and the above authorization code we got from the get request, in the body and it returns the access token
This is how it works in postman. How can I achieve the same thing using Rest Assured?
You need two handlers
Handler 1:
To redirect to oauth server. (requeter should identity list of grant types, generate url with client_id and state and redirect application to this url)
Once end user signs in and allows the grant. (assumed that user allows)
Handler 2:
oauth server redirects back to postman with a authorization_code and state.
You need to configure redirect to your server callback url.
Once you receive these two
Verify state is same as what you sent. if yes proceed.
send authorization_code, cleint_secret, client_id back to server to recieve access_token and refresh_token
Use access_token to access data.
Use refresh_token to get new access_token.

Meaning of 200 response/no errors from dry_run request

dry_run can be set so that pushes aren't sent, but that tokens can be validated by FCM.
If the response to a dry_run is 200 and there are no errors, does that guarantee that if dry_run was not set that there is a an app installation on a device that FCM could target with that message.
The only scenario I can think of is if there is a delay:
dry run enabled in request
user uninstalls the app (or some other event which invalidates the token)
FCM returns 200/no error
FCM receives data relayed from the device that the app was uninstalled and token is invalid
Are there other scenarios?
You can validate the FCM token by calling the
(GET) https://iid.googleapis.com/iid/info/YOUR_APP_TOKEN_HERE
[Header] => 'Authorization: key=YOUR_KEY'
Simple and easy.
If token is valid then it will return 200 status code with some more details in JSON format or if it's invalid then status code will be 400 with error detail in JSON format.
Implement this code server side. get token from database (if you are saving token in database) and passin the above URL and it will send you token status whether if it expired or not.

How to silently refresh expired JWT token with OAuth2?

We have decided to switch from Hazelcast shared session to Stateless JWT authentication/authorization with OAuth2 and found out a problem that doesnt fit our infrastructure described below.
So we have multiple Self-contained systems (scs) that may be accessed by direct link i.e. mysite.com/scs1 and mysite.com/scs2.
Each scs has it's own UI and BackEnd, but "session" (implemented via Stateless JWT Authorization) has to be valid across multiple scs'es.
OAuth2 Authorizaion Server is a dedicated server (UAA).
In the OAuth2 terminology, each scs is a Resource Server.
Let's assume that user has logged into scs1 (via UAA) and got JWT with TTL=10 minutes and RefreshToken with TTL=30 minutes. Then he leaves that tab in browser for 15 minutes. JWT expires, but the tab still contains the previous page from scs1. And user clicks a link on that page that follows to mysite.com/scs3.
scs3 receives a request, checks JWT and finds out that it has expired. But we have a RefreshToken (still alive for 15 minutes) that may refresh JWT.
Is it possible to return a response from scs3 that would ask browser to go to UAA and silently refresh JWT ?
Maybe some kind of REDIRECT to /uaa/authorization with an ability to add RefreshToken Header?
We have finally found out how to deal with token refresh in our case.
JWT has TTL=10min
RefreshToken has TTL=30min
Javascript, embedded in each page of our site refreshes JWT each 8-9 minutes. So when User has an opened tab in his browser, the refresh procedure will happen seamlessly.
A corner case is when User:
Opens tab mysite.com/scs1
Logs in
Closes tab
Waits 15 minutes. JWT expires, RefreshToken is still alive.
Opens new tab and enters mysite.com/scs1 or scs2 etc.
At this point the BackEnd receives only JWT which is expired.
So BackEnd redirects User to a dedicated web-page /try-refresh?uri=mysite.com/scs1
try-refresh page contains ONLY javascript which tries to refresh token and in successful case redirects User back to address from uri parameter

GLUU client does not have permission for SCIM requests

I have a client that is making a getUser SCIM request. It successfully can get an access token and RPT, however when it actually comes to the getUser request, I get a response with the status '403 Forbidden' with a ticket as the body of the response. According to this UMA document a permission ticket indicates the request was valid, but the client does not have permission. I have tried everything I can think of to give this client permissions, but havent managed to get it working.
Does anyone know how to give a client permissions to do SCIM requests?
My current method of attempting a request is:
Get access token using client credentials
Get RPT using access token acquired in step 1 as authorization
make domain.com/identity/seam/resource/restv1/scim/v1/Users request using RPT as authorization
Follow the seek authorization steps of sending request to RPT endpoint with ticket and old RPT. This replies with a new RPT.
Attempt step 3 again using the RPT from step 4 as authorization
Any advice would be appreciated.

Quickbooks API reconnect issue

I've been implementing connectivity to Quickbooks via the v3 API with ColdFusion, and have most everything working except reconnect (https://appcenter.intuit.com/api/v1/connection/reconnect). I can get customer info, create/update invoices, etc, but no luck with reconnect.
From my app I get an Error Code 22 (Authentication required), but I'm sending the same auth header that I send for any of the other API call to access a protected resource. The oauth spec does not specifically have a "reconnect" action so my question is what specific oauth properties need to be included in the auth header for the Quickbooks reconnect call?
From the oauth 1.0 spec is it the headers for Consumer Requests an Access Token?
oauth_consumer_key
oauth_token
oauth_signature_method
oauth_signature
oauth_timestamp
oauth_nonce
oauth_version
oauth_verifier
Or is it the header sent for accessing a protected resource
oauth_consumer_key
oauth_token
oauth_signature_method
oauth_signature:
oauth_timestamp
oauth_nonce
oauth_version
Or, is it some other header set?
Also, I've tried using the Dev Playgorund to test reconnect, and from there I get a
24 - Invalid App Token
So I'm at a loss at this point. For what it's worth Disconnect works fine :)
Any help, guidance, suggestions would be appreciated.
Thanks
The first issue if you are doing things in the order you specify is that you cannot disconnect first and then subsequently reconnect. The reconnect API must be called with a valid access token, as the current access token will be invalidated and a new access token will be issued.
Secondly, there is a window for calling this API to refresh the 6 month life of the access token, it must be called in the last 30 days. This allows your app to refresh the token without prompting the customer again.
However in all cases if you disconnect, or the customer manually disconnects you cannot call the reconnect API. You need to take them through the authorize flow again.
hope that helps
Jarred
To test reconnect from developer playground, use the following steps-
1. Navigate to IPP Playground- Go to Manage My Apps->Click on your app
Fill in consumer key and consumer secret in links below.
Prod: https://appcenter.intuit.com/Playground/OAuth/IA/?ck=<>&cs=<>
Stage: https://appcenter-stage.intuit.com/Playground/OAuth/IA/?ck=<>&cs=<>
Alternatively, you can navigate to the Manage page for your app on stage or prod and click ‘Test connect to app (OAuth)’. Screen shot attached.
2. Enter the duration you would like for the issued OAuth tokens (e.g., 3600 for successful Reconnect) in the ‘Access Token Duration’ field. Screen shot attached.
3. Click on the Connect to QuickBooks button, go through OAuth flow to authorize a connection to a realm.
4. Under the resulting Post-Connection Interactions heading, click ‘Reconnect API Test’. Screen shot attached.
5. A new page will launch where your OAuth tokens are displayed. Copy these values to your application to test Reconnect
As Jarred mentioned that for dev/live apps, there is a window for calling this API to refresh the 6 month life of the access token, it must be called in the last 30 days.
I received this error as well. Error Code 22 (Authentication required) for me meant that the OAuth signature was wrong. This was confusing because I couldn't find this error listed in the Quickbooks documents for reconnect.
I was signing the request as a "POST" request instead of a "GET" request which is what Quickbooks requires for calls to the reconnect endpoint.