AWS Cognito - Programatically get refresh token expiry - amazon-cognito

Refresh token returned from Cognito is not a JWT token , hence cannot be decoded. Is there a way to get the refresh token expiry or it needs to be maintained at application level.

There is no way to decode a refresh token. If you know the expiration time set in cognito for refresh tokens you can store the time it was generated and calculate based on that.

just to elaborate on the accepted answer, as I had the same question.
jwt.org cannot decode the refresh token from aws, as it is encrypted
My way around it, is as follows:
the id token carries "auth_time" (see https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-id-token.html)
on login (you could technically do it on refresh as well), I look at that value and add expiration duration to that for a rough estimate
how to get the expiration duration programmatically? There are probably easier ways to do it, but the sdk-v3 command that worked for me was the 'DescribeUserPoolClientCommand' (https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-cognito-identity-provider/classes/describeuserpoolclientcommand.html)
pseudo code in typescript (used in nodejs backend code) looks something like this:
import { CognitoIdentityProviderClient, DescribeUserPoolClientCommand, DescribeUserPoolClientCommandInput} from "#aws-sdk/client-cognito-identity-provider"
import get from 'lodash/get'
const client = new CognitoIdentityProviderClient({ region: [yourRegion] })
const input = {
UserPoolId: [yourUserPoolId],
ClientId: [yourWebClientId],
} as DescribeUserPoolClientCommandInput
const command = new DescribeUserPoolClientCommand(input)
const response = await client.send(command)
const refreshTokenValidityUnits = get(
response,
"UserPoolClient.TokenValidityUnits.RefreshToken"
)
const refreshTokenValidity = get(
response,
"UserPoolClient.RefreshTokenValidity"
)
// result: "days" and "30" for example
This is obviously not complete enough to get the exact values, but enough to get anyone started who, like me, might not be as familiar with the aws-sdk yet.

Related

updateTenants not working after token refreshed

I'm in the process of updating our app from from oauth 1 to 2. Entire flow works well - I can migrate and save the tokens and access the APIs. However, there is a problem once the original token expires and it gets refreshed. After refreshing, the call to updateTenants does not return any active connections.
My pseudocode is below:
const tokenSet = await getTokenSet(); // Returns saved token set from DB. Assume token is expired!!
const client = new XeroClient(...);
client.setTokenSet(tokenSet);
const newToken = await client.refreshToken();
await saveTokenSet(newToken); // Save to DB
const token = client.readTokenSet();
console.log(token); // Does return my NEW active token set
const tenants = await client.updateTenants(false);
console.log(tenants.body); // This returns an array of length 0
Not clear why the results from updateTenants is empty. I was able to verify this by calling the GET https://api.xero.com/connections endpoint manually with one of the refreshed tokens and also see an empty array in the body.
Any ideas?
I played around with our xero-node-oauth2-app to see if I could recreate this. Here's what I found:
If I connected to my Xero org to obtain valid tokens and then disconnected via the Xero connected apps dashboard and then refreshed my tokens triggering updateTenants the connections endpoint returns an empty array and status code 200. In other words, it's a successful call but Xero doesn't see that the user has authorized your integration to interact with any of their orgs/tenants.
Are you able to verify if your integration is still listed in the connected apps list under settings?
https://community.xero.com/developer/discussion/127403806

Soundcloud API /stream endpoint giving 401 error

I'm trying to write a react native app which will stream some tracks from Soundcloud. As a test, I've been playing with the API using python, and I'm able to make requests to resolve the url, pull the playlists/tracks, and everything else I need.
With that said, when making a request to the stream_url of any given track, I get a 401 error.
The current url in question is:
https://api.soundcloud.com/tracks/699691660/stream?client_id=PGBAyVqBYXvDBjeaz3kSsHAMnr1fndq1
I've tried it without the ?client_id..., I have tried replacing the ? with &, I've tried getting another client_id, I've tried it with allow_redirects as both true and false, but nothing seems to work. Any help would be greatly appreciated.
The streamable property of every track is True, so it shouldn't be a permissions issue.
Edit:
After doing a bit of research, I've found a semi-successful workaround. The /stream endpoint of the API is still not working, but if you change your destination endpoint to http://feeds.soundcloud.com/users/soundcloud:users:/sounds.rss, it'll give you an RSS feed that's (mostly) the same as what you'd get by using the tracks or playlists API endpoint.
The link contained therein can be streamed.
Okay, I think I have found a generalized solution that will work for most people. I wish it were easier, but it's the simplest thing I've found yet.
Use API to pull tracks from user. You can use linked_partitioning and the next_href property to gather everything because there's a maximum limit of 200 tracks per call.
Using the data pulled down in the JSON, you can use the permalink_url key to get the same thing you would type into the browser.
Make a request to the permalink_url and access the HTML. You'll need to do some parsing, but the url you'll want will be something to the effect of:
"https://api-v2.soundcloud.com/media/soundcloud:tracks:488625309/c0d9b93d-4a34-4ccf-8e16-7a87cfaa9f79/stream/progressive"
You could probably use a regex to parse this out simply.
Make a request to this url adding ?client_id=... and it'll give you YET ANOTHER url in its return json.
Using the url returned from the previous step, you can link directly to that in the browser, and it'll take you to your track content. I checked on VLC by inputting the link and it streams correctly.
Hopefully this helps some of you out with your developing.
Since I have the same problem, the answer from #Default motivated me to look for a solution. But I did not understand the workaround with the permalink_url in the steps 2 and 3. The easier solution could be:
Fetch for example user track likes using api-v2 endpoint like this:
https://api-v2.soundcloud.com/users/<user_id>/track_likes?client_id=<client_id>
In the response we can finde the needed URL like mentioned from #Default in his answer:
collection: [
{
track: {
media: {
transcodings:[
...
{
url: "https://api-v2.soundcloud.com/media/soundcloud:tracks:713339251/0ab1d60e-e417-4918-b10f-81d572b862dd/stream/progressive"
...
}
]
}
}
...
]
Make request to this URL with client_id as a query param and you get another URL with that you can stream/download the track
Note that the api-v2 is still not public and the request from your client probably will be blocked by CORS.
As mentioned by #user208685 the solution can be a bit simpler by using the SoundCloud API v2:
Obtain the track ID (e.g. using the public API at https://developers.soundcloud.com/docs)
Get JSON from https://api-v2.soundcloud.com/tracks/TRACK_ID?client_id=CLIENT_ID
From JSON parse MP3 progressive stream URL
From stream URL get MP3 file URL
Play media from MP3 file URL
Note: This link is only valid for a limited amount of time and can be regenerated by repeating steps 3. to 5.
Example in node (with node-fetch):
const clientId = 'YOUR_CLIENT_ID';
(async () => {
let response = await fetch(`https://api.soundcloud.com/resolve?url=https://soundcloud.com/d-o-lestrade/gabriel-ananda-maceo-plex-solitary-daze-original-mix&client_id=${clientId}`);
const track = await response.json();
const trackId = track.id;
response = await fetch(`https://api-v2.soundcloud.com/tracks/${trackId}?client_id=${clientId}`);
const trackV2 = await response.json();
const streamUrl = trackV2.media.transcodings.filter(
transcoding => transcoding.format.protocol === 'progressive'
)[0].url;
response = await fetch(`${streamUrl}?client_id=${clientId}`);
const stream = await response.json();
const mp3Url = stream.url;
console.log(mp3Url);
})();
For a similar solution in Python, check this GitHub issue: https://github.com/soundcloud/soundcloud-python/issues/87

RESTful API using JWT (JSON Web Token) setup token expiry

I'm using JWT for RESTful API (Laravel Web-Services for mobile). How to setup token expiry to never expiry or what the best practice to setup token expiry?
Because currently i need to get the token everytime when the token expired, can anybody have this issue or best solution for token expiry.
There is nothing to make the token never expire. However you can extend the expiration date to a very huge time span, 1 year for example. This is possible, however it is not recommended for security.
In order to achieve that, you need to configure two parts, the token refresh time, and token expiry.
So in config/jwt.php
'refresh_ttl' => 29030400, // Number of minutes in 1 year (12*4*7*24*60*60)
And when you are creating your token, you can pass something like the following
$tokenId = base64_encode(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
$issuedAt = Carbon::now()->timestamp;
$notBefore = $issuedAt; //Adding 10 seconds
$expire = $notBefore + 12*4*7*24*60*60; // Adding 6 hours
/*
* Create the token as an array
*/
$data = [
'iat' => $issuedAt, // Issued at: time when the token was generated
'jti' => $tokenId, // Json Token Id: an unique identifier for the token
'iss' => 'https://example.com', // Issuer
'nbf' => $notBefore, // Not before
'exp' => $expire, // Expire
'data' => [ // Data related to the signed user
'userId' => Auth::user()->id, // userid from the users table
]
];
Now, your token will never expire before 1 year. And you have up to 1 year to refresh it. When the user opens the application the next time, and you authenticate the token, you can refresh it. You can refresh the token, as mentioned in the documentation here. I would recommend going through this laracasts discussion as well.
Also, I have found this question on StackOverflow, I think it will help.

Trying to get streamlive.to rtmp stream to work

How do I get the token?
Their source website says something like this:
var token="";
$.getJSON("http://www.streamlive.to/server.php?id=1431994763", function(json) {
token = json.token;
setStream(token);
});
the token is stored in your variable,named "token"
It was declared when it was defined as the JSON object also named "token", which was established from the getJSON function
you can find your token in the console by typing in the following
console.log(token)
// Do understand that this token expires.. Maybe every 15 min? hour? day? week? month? You should find this out so that you may know how long before you have to get a new token or if you can find a way to redeem/renew the token.

Refresh token giving invalid grant

I am running into an issue with one single user's refresh workflow for Google OAuth. I am correctly scoping for offline access and am storing that. Every 60 minutes, when needed, I retrieve a new access_token. Code has not changed, but what is odd is that when he first went through the authorization process it worked for about 3 days. Then we were running this issue, so I made him revoke access and go through the authorization again. This only lasted for 3 days once again.
client_id ="xxxxx.apps.googleusercontent.com"
client_secret ="yyyyyyyy"
refresh_token ="zzzzzzzz"
response = oauth2a.RefreshToken(client_id,client_secret,refresh_token)
def RefreshToken(client_id, client_secret, refresh_token):
params = {}
params['client_id'] = client_id
params['client_secret'] = client_secret
params['refresh_token'] = refresh_token
params['grant_type'] = 'refresh_token'
request_url = AccountsUrl('o/oauth2/token')
response = urllib.urlopen(request_url, urllib.urlencode(params)).read()
return json.loads(response)
The response is always {u'error': u'invalid_grant'}. I have attempted this on three different machines, so the NTP time sync is not the issue as well. All other user's refresh works fine. I am also never asking for a refresh_token again, so I know I'm not running into that 25 refresh_token limit. This is looking like it's a bug on the gmail side, is there any way that I can proceed to try to fix this?