amplify-js
amplify-js copied to clipboard
Unable to exchange Google federated identity id token for Cognito access token
Before opening, please confirm:
- [X] I have searched for duplicate or closed issues and discussions.
- [X] I have read the guide for submitting bug reports.
- [X] I have done my best to include a minimal, self-contained set of instructions for consistently reproducing the issue.
JavaScript Framework
React
Amplify APIs
Authentication
Amplify Version
v6
Amplify Categories
auth
Backend
Other
Environment information
# Put output below this line
System:
OS: Windows 11 10.0.22631
CPU: (12) x64 Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz
Memory: 3.03 GB / 15.72 GB
Binaries:
Node: 18.20.4 - C:\Program Files\nodejs\node.EXE
npm: 10.2.3 - C:\Program Files\nodejs\npm.CMD
Browsers:
Edge: Chromium (127.0.2651.74)
Internet Explorer: 11.0.22621.3527
npmPackages:
@arcgis/core: ^4.28.10 => 4.28.10
@aws-amplify/ui-react: ^6.1.4 => 6.1.4
@aws-amplify/ui-react-internal: undefined ()
@aws-sdk/client-cognito-identity: ^3.620.0 => 3.620.0
@headlessui/react: 2.0 => 2.0.4
@heroicons/react: ^2.1.3 => 2.1.3
@material-tailwind/react: ^2.1.9 => 2.1.9
@tailwindcss/forms: ^0.5.7 => 0.5.7
@types/react: ^18.2.55 => 18.2.56
@types/react-dom: ^18.2.19 => 18.2.19
@vitejs/plugin-react: ^4.2.1 => 4.2.1
autoprefixer: ^10.4.17 => 10.4.17
aws-amplify: ^6.0.17 => 6.0.17
aws-amplify/adapter-core: undefined ()
aws-amplify/analytics: undefined ()
aws-amplify/analytics/kinesis: undefined ()
aws-amplify/analytics/kinesis-firehose: undefined ()
aws-amplify/analytics/personalize: undefined ()
aws-amplify/analytics/pinpoint: undefined ()
aws-amplify/api: undefined ()
aws-amplify/api/server: undefined ()
aws-amplify/auth: undefined ()
aws-amplify/auth/cognito: undefined ()
aws-amplify/auth/cognito/server: undefined ()
aws-amplify/auth/enable-oauth-listener: undefined ()
aws-amplify/auth/server: undefined ()
aws-amplify/datastore: undefined ()
aws-amplify/in-app-messaging: undefined ()
aws-amplify/in-app-messaging/pinpoint: undefined ()
aws-amplify/push-notifications: undefined ()
aws-amplify/push-notifications/pinpoint: undefined ()
aws-amplify/storage: undefined ()
aws-amplify/storage/s3: undefined ()
aws-amplify/storage/s3/server: undefined ()
aws-amplify/storage/server: undefined ()
aws-amplify/utils: undefined ()
eslint: ^8.56.0 => 8.56.0
eslint-plugin-react: ^7.33.2 => 7.33.2
eslint-plugin-react-hooks: ^4.6.0 => 4.6.0
eslint-plugin-react-refresh: ^0.4.5 => 0.4.5
express: ^4.18.2 => 4.18.2
postcss: ^8.4.35 => 8.4.35
react: ^18.2.0 => 18.2.0
react-dom: ^18.2.0 => 18.2.0
react-router-dom: ^6.22.1 => 6.22.1
tailwindcss: ^3.4.3 => 3.4.3
vite: ^5.1.0 => 5.1.3
npmGlobalPackages:
@aws-amplify/cli: 12.12.4
http-server: 14.1.1
npm: 10.2.3
pm2: 5.3.1
Describe the bug
I've currently implemented a customCredentialsProvider (as shown here - https://docs.amplify.aws/react/build-a-backend/auth/advanced-workflows/) to federate an a Google identity. I successfully receive the credential from Google. I then created a customTokenProvider (as shown here - https://docs.amplify.aws/react/build-a-backend/auth/advanced-workflows/#custom-token-providers)
My issue is that I don't receive the Cognito tokens JwtBearer auth and using the Cognito user pool as the issuer.
https://cognito-idp.us-east-1.amazonaws.com/{userPoolId}
Expected behavior
After receiving the response.credential from Google, I would expect to be able to exchange the id_token that's returned for valid Cognito tokens so I can access my backend API.
Reproduction steps
Launch google sign in as shown here : https://docs.amplify.aws/react/build-a-backend/auth/advanced-workflows/#google-sign-in-react
Successfully auth with Google
Code Snippet
// Put your code below this line.
import { Amplify } from "aws-amplify";
import {
fetchAuthSession,
CredentialsAndIdentityIdProvider,
CredentialsAndIdentityId,
GetCredentialsOptions,
AuthTokens,
} from "aws-amplify/auth";
// Note: This example requires installing `@aws-sdk/client-cognito-identity` to obtain Cognito credentials
// npm i @aws-sdk/client-cognito-identity
import { CognitoIdentity } from "@aws-sdk/client-cognito-identity";
// You can make use of the sdk to get identityId and credentials
const cognitoidentity = new CognitoIdentity({
region: "us-east-1",
});
// Note: The custom provider class must implement CredentialsAndIdentityIdProvider
class CustomCredentialsProvider implements CredentialsAndIdentityIdProvider {
// Example class member that holds the login information
federatedLogin?: {
domain: string;
token: string;
};
// Custom method to load the federated login information
loadFederatedLogin(login?: typeof this.federatedLogin) {
// You may also persist this by caching if needed
this.federatedLogin = login;
}
async getCredentialsAndIdentityId(
getCredentialsOptions: GetCredentialsOptions
): Promise<CredentialsAndIdentityId | undefined> {
try {
// You can add in some validation to check if the token is available before proceeding
// You can also refresh the token if it's expired before proceeding
const getIdResult = await cognitoidentity.getId({
// Get the identityPoolId from config
IdentityPoolId: "<identity-pool-id>",
Logins: { [this.federatedLogin.domain]: this.federatedLogin.token },
});
const cognitoCredentialsResult =
await cognitoidentity.getCredentialsForIdentity({
IdentityId: getIdResult.IdentityId,
Logins: { [this.federatedLogin.domain]: this.federatedLogin.token },
});
const credentials: CredentialsAndIdentityId = {
credentials: {
accessKeyId: cognitoCredentialsResult.Credentials?.AccessKeyId,
secretAccessKey: cognitoCredentialsResult.Credentials?.SecretKey,
sessionToken: cognitoCredentialsResult.Credentials?.SessionToken,
expiration: cognitoCredentialsResult.Credentials?.Expiration,
},
identityId: getIdResult.IdentityId,
};
return credentials;
} catch (e) {
console.log("Error getting credentials: ", e);
}
}
// Implement this to clear any cached credentials and identityId. This can be called when signing out of the federation service.
clearCredentialsAndIdentityId(): void {}
}
const customCredentialsProvider = new CustomCredentialsProvider();
export { customCredentialsProvider };
Log output
// Put your logs below this line
aws-exports.js
export const awsExports = {
Cognito: {
region: "region",
userPoolId: "",
userPoolClientId: "",
identityPoolId: "",
loginWith: {
oauth: {
domain: "user-pool-domain",
scopes: ["email", "profile", "openid", "aws.cognito.signin.user.admin"],
redirectSignIn: [
"http://localhost"
],
redirectSignOut: ["http://localhost"],
responseType: "code", // or 'token', note that REFRESH token will only be generated when the responseType is code
},
},
},
};
Manual configuration
No response
Additional configuration
No response
Mobile Device
No response
Mobile Operating System
No response
Mobile Browser
No response
Mobile Browser Version
No response
Additional information and screenshots
No response
Hello, @david-sunsyte 👋. Trying to understand how to reproduce this figure out the root cause of what's blocking you here. Can you clarify where the tokens are coming from in your implementation of your customer token provider? Are you using TokenProvider somewhere else in the code that's not referenced in this issue (example from docs)?
Also, is Google the IDP for your User Pool? I'm not understanding the need for the Custom Token Provider aspect if you're looking to just use Google as a federated IDP. Any additional context/clarity on the above items would be appreciated. Thanks!
Hi @cwomack , thank you so much for your reply. The tokens are coming from the callback from the google initialize function shown below:
window.google.accounts.id.initialize({
client_id: process.env.GOOGLE_CLIENT_ID,
callback: (response: any) => {
customCredentialsProvider.loadFederatedLogin({
domain: 'accounts.google.com',
token: response.credential,
});
const fetchSessionResult = await fetchAuthSession(); // will return the credentials
console.log('fetchSessionResult: ', fetchSessionResult);
},
});
Granted, I did this as a long shot and in the absence of being able to identify my issue. The overall problem I'm trying to solve is for is to authenticate via Google and retrieve a token that can then be exchanged for Cognito tokens (preferrably id_token) so I can access my backend API.
I may not need to use the custom token provider to achieve this, I just don't know which way to go with this.
Hello @david-sunsyte.
You might want to use a custom token provider to make authenticated calls to AppSync— assuming AppSync was configured to accept OIDC tokens before.
And you might want to use a custom credentials provider to generate AWS Credentials without using Cognito User Pools, hence avoiding creating Cognito tokens and being unable to call the cognito-idp endpoints.
If you want to create Cognito tokens, use Google as your social provider, and also create AWS Credentials. You need to configure your User Pool with Google, configure Amplify, and then call the signInWithRedirect API to authenticate to Google. Once you have this setup, you don't need to setup a custom token and credentials provider.
-docs to configure and use social providers with Amplify: https://docs.amplify.aws/react/build-a-backend/auth/concepts/external-identity-providers/
Closing this issue as we have not heard back from you. If you are still experiencing this, please feel free to reply back and provide any information previously requested and we'd be happy to re-open the issue.
Thank you!