-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
How to refresh Cognito tokens #446
Comments
i literally tried everything, still doesn't work. methods i tried:
|
I would like to achieve the same with amplify library. |
I had used
To refresh user session, are you using the same? |
Yes, i'm pretty much doing the same thing. I've tried many variations. |
If this is a bug, could you try with different version of aws cognito packages? |
I was using a ~ 1 year old version, than updated to the latest version of cognito and cognito identity, both didn't work. |
I am also trying to figure this out, anyone have any luck? |
Since i can only refresh successfully once i'm doing it like this now:
If one of you guys come up with a proper solution for this, please post them here. i'd be really happy. |
|
How about this? It is from AUTH library itself, with some modifications
} |
I have the same issue. I have taken to forcing the user to do a page reload. |
I'd also like to know what the best way of doing this is; calling |
There seems to be a lot of questions on how to do this. Could it be possible that an example of this be added to the documentation? |
yeeeeeeeeeeeeeeeeeeeeeeeeeeeah, after almost 2 weeks i finally solved it. You need the Refresh Token to receive a new Id Token. Once the Refreshed Token is acquired, update the here's an example on how to set this up, runs smoothly!
|
@tipsfedora thank you very much for this! I will definitely check it out!! |
Closing the issue. Feel free to reopen it if necessary. |
It would be nice to get some guidance on how to do this with the Amplify lib. It appears to me that the session is automatically refreshed if expired, but there is no way to refresh the token early. Is that the case? |
@retwedt that's correct, the session is automatically refreshed, you could technically refresh the token yourself however by doing this same approach since the amplify lib uses the cognito lib under the covers. We are working on giving more flexibility / simplifying this as well (in our backlog) to both refresh and also disable automatic refresh. |
Great thanks! |
I wasn't sur about how to manage the refresh token and how to ask for id and access tokens, so if we are using aws amplify, all this is happened under cover, I don't have to ask for new id token or access token right ? |
@Jasminou yes aws amplify will refresh your session automatically if expired. |
It will refresh if you call the SDK for it, e.g., with Auth.currentSession(), and it finds an expired token + a valid refresh token. AFAIK there's no timing mechanism to update your localStorage for you in the background. (Auth0's JS SDK uses setTimeout to update localStorage, but that's got its own issues.) If like me you're using Amplify just for the auth, and doing the rest with REST, then you'll want to call Auth.currentSession() before every API call, to get the latest access token. E.g. using Axios HTTP request framework:
|
@jamesoflol yes. The session will be refreshed when calling |
@jamesoflol It's probably a good idea to catch |
@StevenDufresne Agreed. I'll update my example as it seems this issue gets some traffic |
@david114 the solution that you proposed actually giving me an exception repeatedly: |
What Libaries are you using? Our Website is quite old now and we are not using AWS Amplify at all. We're using: Using these files, I can call AWS.config.credentials.params.Logins without any problems |
@david114 thanks for the reply. I am working on node-js and using amazon-cognito-identity-js. I guess you have utilized in another JavaScript. |
@ripundeep we were using plain client-sided javascript |
FWIW in case it helps anyone else, I was initially thinking that Feels like a bug that no event is fired when a refresh token happens. So for now I've added an axios interceptor to insert the token from |
@jeffsheets - care to share the code you used for that interceptor in case it might be useful to others? |
@justingrant Oh yep, here you go! This uses the Axios Interceptors setup to inject the Auth token on every call. I can't remember why our app uses idToken instead of accessToken, so depending on the app that might have to change, but here's the general idea. https://github.com/axios/axios#interceptors export const axiosRequestInterceptor = async config => {
//This will get the cached session, or refresh the token first if it has expired
const session = await Auth.currentSession();
if (session && session.idToken) {
config.headers.Authorization = session.idToken.jwtToken;
}
return config;
};
axios.interceptors.request.use(axiosRequestInterceptor, e => Promise.reject(e)); |
This is what I do with axios on every request: axios.interceptors.request.use(async function (config: AxiosRequestConfig) {
const session = await Auth.currentSession()
try {
const token = session.getAccessToken().getJwtToken()
config.headers.authorization = token
} catch (error) {
log.error(error)
await store.dispatch('auth/logout')
await router.push({
name: 'login'
})
}
return config
}, async function (error: AxiosError) {
return Promise.reject(error)
}) And because sometimes my users get logged out randomly, I refresh the token manually on an interval (still experimenting with this): let cognitoKeepaliveInterval: any = null
function startCognitoKeepaliveInterval() {
if (cognitoKeepaliveInterval) clearInterval(cognitoKeepaliveInterval)
cognitoKeepaliveInterval = setInterval(async () => {
const session = await Auth.currentSession()
const user = await Auth.currentAuthenticatedUser()
user.refreshSession(session.getRefreshToken(), () => {
log.info('refreshed auth session')
})
}, 30 * 60 * 1000) // 30 minutes
} |
Well, i don't understand — if i console.log session token it remains the same:
So... what is the point of running the |
@artuska , from the documentation: https://aws-amplify.github.io/docs/js/authentication#retrieve-current-session
|
Thank you for your solution. We had the same issue with large uploads. We tried many solutions but none of them worked for us. A good start is to check We created a custom import { AWS } from "@aws-amplify/core";
import { Auth } from "aws-amplify";
export default class Storage {
private _refreshTimeout;
// Token expiration is 60 min
private readonly REFRESH_INTERVAL = 50 * 60 * 1000; // 50 min
private readonly MIN_REFRESH_INTERVAL = 30 * 1000; // 30 sec
private readonly COGNITO_IDP_URL;
constructor({ region, userPoolId }) {
this.COGNITO_IDP_URL = `cognito-idp.${region}.amazonaws.com/${userPoolId}`;
}
private _clean = () => {
if (this._refreshTimeout) {
clearTimeout(this._refreshTimeout);
this._refreshTimeout = null;
}
};
private _scheduleCredentialsRefresh = (interval = this.REFRESH_INTERVAL) => {
this._refreshTimeout = setTimeout(async () => {
const session = await Auth.currentSession();
// @ts-ignore
AWS.config.credentials.params.Logins[
this.COGNITO_IDP_URL
] = session.getIdToken().getJwtToken();
// @ts-ignore
AWS.config.credentials.refresh(async error => {
if (this._refreshTimeout) {
this._scheduleCredentialsRefresh(
error ? this.MIN_REFRESH_INTERVAL : this.REFRESH_INTERVAL
);
}
});
}, interval);
};
private _createS3 = ({ bucket, region, ...restParams }) => {
// @ts-ignore
return new AWS.S3({
apiVersion: "2006-03-01",
signatureVersion: "v4",
params: { Bucket: bucket },
region,
...restParams,
});
};
private _initCredentials = async () => {
try {
const credentials = await Auth.currentUserCredentials();
AWS.config.credentials = credentials;
return credentials;
} catch (e) {
return null;
}
};
private _getParams = ({ credentials, level = "public", key, object }) => {
if (!credentials && level !== "public") {
throw new Error("Missing credentials");
}
let prefix;
const identityId = credentials.identityId;
switch (level) {
case "public":
prefix = "public";
break;
case "protected":
prefix = `protected/${identityId}`;
break;
case "private":
prefix = `private/${identityId}`;
break;
}
return {
// @ts-ignore
Key: `${prefix}/${key}`,
Body: object,
ContentType: "binary/octet-stream",
};
};
public put = (
key,
object,
{ progressCallback, level, bucket, region, ...restParams }
) =>
new Promise(async (resolve, reject) => {
try {
const credentials = await this._initCredentials();
const s3 = this._createS3({ bucket, region, ...restParams });
const params = this._getParams({ credentials, level, key, object });
if (credentials) {
this._scheduleCredentialsRefresh();
}
s3.upload(params)
.on("httpUploadProgress", progressCallback)
.promise()
.then(data => {
this._clean();
resolve(data);
})
.catch(error => {
this._clean();
reject(error);
});
} catch (error) {
this._clean();
reject(error);
}
});
}
export const MyStorage = new Storage({
region: "your-region",
userPoolId: "your-user-pool-id",
}); U can use MyStorage.put(`fileName`, file, {
progressCallback: onProgress,
level: "private",
bucket: "bucket",
region: "region",
})
.then(onSuccess)
.catch(onFailure); The token is refreshed every 50 min (REFRESH_INTERVAL). If the refresh fails for some reason we are still trying to refresh the token every 30 sec (MIN_REFRESH_INTERVAL). |
@norbertdurcansk trying your custom storage class now as a shortcut, If it works, I will buy you a coffee after the pandemic :) |
After some trial and error I have found that the answer from @jamesoflol is the most correct. /**
* As the AWS Amplify SDK does not notify when the current access token expires
* we have to check the current token on every HTTP call. This class
* implements an HTTP request interceptor for the Angular HttpClient
*/
@Injectable()
export class AddAccessTokenToHttpHeader implements HttpInterceptor
{
constructor(protected amplify_service: AmplifyService)
{
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
{
// Amplify AuthClass.currentSession() checks the
// access token and refreshes it if required.
return (from((this.amplify_service.auth() as AuthClass).currentSession()).pipe(
switchMap(cognito_session =>
{
let auth_header: string = 'Bearer ' + cognito_session.getAccessToken().getJwtToken()
let new_request: HttpRequest<any> = request.clone({
setHeaders: {
Authorization: auth_header
}
});
return (next.handle(new_request));
})
));
}
}``` |
This issue has been automatically closed because of inactivity. Please open a new issue if are still encountering problems. |
How would you re-route the request on an unauthorized request? |
This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs. Looking for a help forum? We recommend joining the Amplify Community Discord server |
There is a similar issue in #405, but the OP uses old approach, I would like to know how to refresh tokens based on aws-amplify library?
Also, this is probably related, how could I make sure that the user is always logged in?
The text was updated successfully, but these errors were encountered: