I am authenticating through Cognito on client side browser using a developer authenticated identity. When my page loads (or is refreshed) I would like my application to remember the Identity for as long as the object is not expired (I think it lasts about an hour). However, I don't know how to retrieve the identity from Cognito without having to go through the developer authentication again.
Here is what the code does on page load:
var cognitoCredentials
$(document).ready(function() {
"use strict";
cognitoParams = {
IdentityPoolId: 'us-east-1:xxxxxxx'
};
cognitoCredentials = new AWS.CognitoIdentityCredentials(cognitoParams);
AWS.config.credentials = cognitoCredentials;
});
And after logging in through the developer authentication:
cognitoCredentials.params.IdentityId = output.identityId;
cognitoCredentials.params.Logins = {
'cognito-identity.amazonaws': output.token
};
cognitoCredentials.expired = true;
If I have already logged in, and then refresh the page, and try to log in again I get an error that I am trying to get an identity when I already have one
Error: Missing credentials in config(…) NotAuthorizedException: Missing credentials in config
"Access to Identity 'us-east-1:xxxxxxx' is forbidden."
However, I don't know how to access it. How do I retrieve the credentials so that when the page is refreshed, I can detect the previous identity given by Cognito?
I am authenticating through Cognito on client side browser using a developer authenticated identity. When my page loads (or is refreshed) I would like my application to remember the Identity for as long as the object is not expired (I think it lasts about an hour). However, I don't know how to retrieve the identity from Cognito without having to go through the developer authentication again.
Here is what the code does on page load:
var cognitoCredentials
$(document).ready(function() {
"use strict";
cognitoParams = {
IdentityPoolId: 'us-east-1:xxxxxxx'
};
cognitoCredentials = new AWS.CognitoIdentityCredentials(cognitoParams);
AWS.config.credentials = cognitoCredentials;
});
And after logging in through the developer authentication:
cognitoCredentials.params.IdentityId = output.identityId;
cognitoCredentials.params.Logins = {
'cognito-identity.amazonaws.com': output.token
};
cognitoCredentials.expired = true;
If I have already logged in, and then refresh the page, and try to log in again I get an error that I am trying to get an identity when I already have one
Error: Missing credentials in config(…) NotAuthorizedException: Missing credentials in config
"Access to Identity 'us-east-1:xxxxxxx' is forbidden."
However, I don't know how to access it. How do I retrieve the credentials so that when the page is refreshed, I can detect the previous identity given by Cognito?
Share Improve this question edited Aug 15, 2019 at 12:08 JBaczuk asked Sep 16, 2015 at 15:12 JBaczukJBaczuk 14.6k10 gold badges65 silver badges90 bronze badges3 Answers
Reset to default 13Save at least accessKeyId, secretAccessKey, sessionToken
in sessionStorage
between pages. You can load these into AWS.config.credentials (after the AWS SDK has been loaded of course). It is much faster than waiting for Cognito to respond. Keep in mind, you'll have to manually refresh them with a token from one of the providers and this is only good until the temporary token expires (~1 hour).
var credKeys = [
'accessKeyId',
'secretAccessKey',
'sessionToken'
];
// After Cognito login
credKeys.forEach(function(key) {
sessionStorage.setItem(key, AWS.config.credentials[key]);
});
// After AWS SDK load
AWS.config.region = 'us-east-1'; // pick your region
credKeys.forEach(function(key) {
AWS.config.credentials[key] = sessionStorage.getItem(key);
});
// Now make your AWS calls to S3, DynamoDB, etc
The only way to get back to the same identity on page refresh would be to use the same token used to initialize that identity. You may want to refer to this question as the problems are similar (replacing the Facebook token with the OpenId Connect token from the developer authenticated identities flow).
To reiterate what that question says: the credentials in the SDK will not be persisted across pages, so you should cache the token to be reused.
I take a slightly different approach, that allows the SDK to refresh the credentials.
In short, I serialize the AssumeRoleWithWebIdentityRequest
JSON object to session storage.
Here is an example using Angular, but concept applies in any JS app:
const AWS = require('aws-sdk/global');
import { STS } from 'aws-sdk';
import { environment } from '../../environments/environment';
const WEB_IDENT_CREDS_SS_KEY = 'ic.tmpAwsCreds';
// Handle tmp aws creds across page refreshes
const tmpCreds = sessionStorage.getItem(WEB_IDENT_CREDS_SS_KEY);
if (!!tmpCreds) {
AWS.config.credentials = new AWS.WebIdentityCredentials(JSON.parse(tmpCreds));
}
@Injectable({
providedIn: 'root'
})
export class AuthService {
...
async assumeAwsRoleFromWebIdent(fbUser: firebase.User) {
const token = await fbUser.getIdToken(false);
let p: STS.Types.AssumeRoleWithWebIdentityRequest = {
...environment.stsAssumeWebIdentConfig,
//environment.stsAssumeWebIdentConfig contains:
//DurationSeconds: 3600,
//RoleArn: 'arn:aws:iam::xxx:role/investmentclub-fbase-trust',
RoleSessionName: fbUser.uid + '@' + (+new Date()),
WebIdentityToken: token
};
// Store creds across page refresh, duno WTF `new AWS.WebIdentityCredentials(p)` don't have an option for this
AWS.config.credentials = new AWS.WebIdentityCredentials(p);
sessionStorage.setItem(WEB_IDENT_CREDS_SS_KEY, JSON.stringify(p));
}
removeAwsTempCreds() {
AWS.config.credentials = {};
sessionStorage.removeItem(WEB_IDENT_CREDS_SS_KEY);
}
...
Few things to note:
- Upon login, I store the
WebIdentityCredentials
parameters as a JSON string in session cache. - You'll notice I check the browser session cache in global scope, to handle page refreshes (sets creds before they can be used).
A tutorial with complete example can be found on my blog