aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.42k stars 2.12k forks source link

Amplify-JS Has No Provision For Making REST API Calls Using Temporary Credentials #8381

Open slimandslam opened 3 years ago

slimandslam commented 3 years ago

Before opening, please confirm:

JavaScript Framework

React, Not applicable

Amplify APIs

REST API

Amplify Categories

api

Environment information

``` # Put output below this line System: OS: macOS 11.4 CPU: (6) x64 Intel(R) Core(TM) i5-8500B CPU @ 3.00GHz Memory: 525.64 MB / 16.00 GB Shell: 3.2.57 - /bin/bash Binaries: Node: 14.16.0 - ~/tinfo/virtenv/bin/node Yarn: 1.22.10 - /usr/local/bin/yarn npm: 6.14.11 - ~/tinfo/virtenv/bin/npm Browsers: Chrome: 91.0.4472.77 Firefox: 88.0.1 Safari: 14.1.1 npmPackages: @aws-sdk/client-cognito-identity: ^3.16.0 => 3.16.0 (3.6.1) @aws-sdk/client-sts: ^3.16.0 => 3.16.0 @aws-sdk/credential-provider-cognito-identity: ^3.16.0 => 3.16.0 (3.6.1) @testing-library/jest-dom: ^5.12 => 5.12.0 @testing-library/react: ^11.2.7 => 11.2.7 @testing-library/user-event: ^13.1.9 => 13.1.9 aws-amplify: ^4.0.2 => 4.0.2 aws-amplify-react: ^5.0.0 => 5.0.0 eslint: ^7.26.0 => 7.27.0 nanoid: ^3.1.23 => 3.1.23 (2.1.11) prettier: ^2.3.0 => 2.3.0 rc-slider: ^9.7.2 => 9.7.2 react: ^17.0.2 => 17.0.2 react-bootstrap: ^1.6.0 => 1.6.0 react-bootstrap-sweetalert: ^5.2.0 => 5.2.0 react-bootstrap/AbstractNav: undefined () react-bootstrap/AbstractNavItem: undefined () react-bootstrap/Accordion: undefined () react-bootstrap/AccordionCollapse: undefined () react-bootstrap/AccordionContext: undefined () react-bootstrap/AccordionToggle: undefined () react-bootstrap/Alert: undefined () react-bootstrap/Badge: undefined () react-bootstrap/BootstrapModalManager: undefined () react-bootstrap/Breadcrumb: undefined () react-bootstrap/BreadcrumbItem: undefined () react-bootstrap/Button: undefined () react-bootstrap/ButtonGroup: undefined () react-bootstrap/ButtonToolbar: undefined () react-bootstrap/Card: undefined () react-bootstrap/CardColumns: undefined () react-bootstrap/CardContext: undefined () react-bootstrap/CardDeck: undefined () react-bootstrap/CardGroup: undefined () react-bootstrap/CardImg: undefined () react-bootstrap/Carousel: undefined () react-bootstrap/CarouselCaption: undefined () react-bootstrap/CarouselItem: undefined () react-bootstrap/CloseButton: undefined () react-bootstrap/Col: undefined () react-bootstrap/Collapse: undefined () react-bootstrap/Container: undefined () react-bootstrap/Dropdown: undefined () react-bootstrap/DropdownButton: undefined () react-bootstrap/DropdownItem: undefined () react-bootstrap/DropdownMenu: undefined () react-bootstrap/DropdownToggle: undefined () react-bootstrap/ElementChildren: undefined () react-bootstrap/Fade: undefined () react-bootstrap/Feedback: undefined () react-bootstrap/Figure: undefined () react-bootstrap/FigureCaption: undefined () react-bootstrap/FigureImage: undefined () react-bootstrap/Form: undefined () react-bootstrap/FormCheck: undefined () react-bootstrap/FormCheckInput: undefined () react-bootstrap/FormCheckLabel: undefined () react-bootstrap/FormContext: undefined () react-bootstrap/FormControl: undefined () react-bootstrap/FormFile: undefined () react-bootstrap/FormFileInput: undefined () react-bootstrap/FormFileLabel: undefined () react-bootstrap/FormGroup: undefined () react-bootstrap/FormLabel: undefined () react-bootstrap/FormText: undefined () react-bootstrap/Image: undefined () react-bootstrap/InputGroup: undefined () react-bootstrap/Jumbotron: undefined () react-bootstrap/ListGroup: undefined () react-bootstrap/ListGroupItem: undefined () react-bootstrap/Media: undefined () react-bootstrap/Modal: undefined () react-bootstrap/ModalBody: undefined () react-bootstrap/ModalContext: undefined () react-bootstrap/ModalDialog: undefined () react-bootstrap/ModalFooter: undefined () react-bootstrap/ModalHeader: undefined () react-bootstrap/ModalTitle: undefined () react-bootstrap/Nav: undefined () react-bootstrap/NavContext: undefined () react-bootstrap/NavDropdown: undefined () react-bootstrap/NavItem: undefined () react-bootstrap/NavLink: undefined () react-bootstrap/Navbar: undefined () react-bootstrap/NavbarBrand: undefined () react-bootstrap/NavbarCollapse: undefined () react-bootstrap/NavbarContext: undefined () react-bootstrap/NavbarToggle: undefined () react-bootstrap/Overlay: undefined () react-bootstrap/OverlayTrigger: undefined () react-bootstrap/PageItem: undefined () react-bootstrap/Pagination: undefined () react-bootstrap/Popover: undefined () react-bootstrap/PopoverContent: undefined () react-bootstrap/PopoverTitle: undefined () react-bootstrap/ProgressBar: undefined () react-bootstrap/ResponsiveEmbed: undefined () react-bootstrap/Row: undefined () react-bootstrap/SafeAnchor: undefined () react-bootstrap/SelectableContext: undefined () react-bootstrap/Spinner: undefined () react-bootstrap/SplitButton: undefined () react-bootstrap/Switch: undefined () react-bootstrap/Tab: undefined () react-bootstrap/TabContainer: undefined () react-bootstrap/TabContent: undefined () react-bootstrap/TabContext: undefined () react-bootstrap/TabPane: undefined () react-bootstrap/Table: undefined () react-bootstrap/Tabs: undefined () react-bootstrap/ThemeProvider: undefined () react-bootstrap/Toast: undefined () react-bootstrap/ToastBody: undefined () react-bootstrap/ToastContext: undefined () react-bootstrap/ToastHeader: undefined () react-bootstrap/ToggleButton: undefined () react-bootstrap/ToggleButtonGroup: undefined () react-bootstrap/Tooltip: undefined () react-bootstrap/createChainedFunction: undefined () react-bootstrap/createWithBsPrefix: undefined () react-bootstrap/divWithClassName: undefined () react-bootstrap/helpers: undefined () react-bootstrap/transitionEndListener: undefined () react-bootstrap/triggerBrowserReflow: undefined () react-bootstrap/types: undefined () react-bootstrap/usePopperMarginModifiers: undefined () react-bootstrap/useWrappedRefWithWarning: undefined () react-data-table-component: ^6.11.7 => 6.11.7 react-dom: ^17.0.2 => 17.0.2 react-dropzone: ^11.3.2 => 11.3.2 react-icons: ^4.2.0 => 4.2.0 react-router-bootstrap: ^0.25.0 => 0.25.0 react-router-dom: ^5.2.0 => 5.2.0 react-scripts: 4.0.3 => 4.0.3 styled-components: ^5.3.0 => 5.3.0 styled-components/macro: undefined () styled-components/native: undefined () styled-components/primitives: undefined () web-vitals: ^1.1.2 => 1.1.2 npmGlobalPackages: npm: 6.14.11 ```

Describe the bug

There appears to be no way to make an API call using a generated set of credentials. I generated temporary credentials:

const tempCredentials = {
      accessKeyId: AccessKeyId,
      secretAccessKey: SecretAccessKey,
      sessionToken: SessionToken,
    };

I want to use them in an Amplify-JS call like this:

API.get("mybackend", "/api/v1/somecall");

However, there doesn't seem to be a way to do that.

Expected behavior

I'm expecting a clear way to use temporary credentials in an Amplify-JS API call.

Reproduction steps

  1. install Amplify-JS
  2. configure Cognito and the Unauthenticated Cognito user.
  3. generate temporary credentials
  4. attempt to make an API call

Code Snippet

// Put your code below this line.

Log output

``` // Put your logs below this line ```

aws-exports.js

No response

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

chrisbonifacio commented 3 years ago

I think if you just need to get those credentials over to the api in your request, you may be able to set them in the third argument to API.get as documented here:

https://docs.amplify.aws/lib/restapi/fetch/q/platform/js

You can set them in the headers or as query parameters, etc, for use in determining your API response.

Let me know if this helps!

slimandslam commented 3 years ago

Those credentials are temporary credentials for a Cognito Unauthenticated user. They are needed for authentication with API Gateway (but a Lambda function will also consume them). In any case, the link you provided does not have an example of how to include these temporary credentials. Typically, they have to be handled in a specific way with specific case sensitivity (e.g. "sessionToken: SessionToken", not "SessionToken: Sessiontoken")

One of the great things about Amplify is that you can use API Gateway, as an authenticated Cognito user, with minimal config, and do calls like this: API.get("mybackend", "/api/v1/somecall");

However, I don't see the syntax for how to do this call if I'm a temporary user (using a Role that allows the API Gateway call). I can generate the temp credentials, but how do I use them?

chrisbonifacio commented 3 years ago

Sorry, there are still gaps in my knowledge of the Auth category. May I ask how you are generating the credentials and how you intend to use them in your API?

I'm not sure that you need to generate credentials to make the api call. It sounds like Amplify might handle that for you. Are you receiving an error when calling API.get?

https://docs.amplify.aws/lib/restapi/authz/q/platform/js/#unauthenticated-requests

slimandslam commented 3 years ago

This is not an unauthenticated request. It's a Cognito Unauthenticated user making a request. The Cognito Unauthenticated user has a role (stored in Cognito) which lets the Cognito Unauthenticated user do only things specified in that role.

To create the temporary credentials, I had to use three API calls: GetIdCommand() GetOpenIdTokenCommand() AssumeRoleWithWebIdentityCommand()

The last call required the Cognito UNauthenticated role ARN.

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] commented 3 years ago

This issue has been automatically closed because of inactivity. Please open a new issue if are still encountering problems.

chrisbonifacio commented 3 years ago

Hi :wave: Sorry this was auto-closed by stale bot. We are working towards preventing this from happening in the future. Please let us know if you are still experiencing this issue and in need of assistance.

slimandslam commented 3 years ago

Thanks!

On Fri, Jul 23, 2021 at 1:15 PM Chris Bonifacio @.***> wrote:

Hi 👋 Sorry this was auto-closed by stale bot. We are working towards preventing this from happening in the future. Please let us know if you are still experiencing this issue and in need of assistance.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/aws-amplify/amplify-js/issues/8381#issuecomment-885890779, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABYBR4UFHWC4YW7PYIKJSDTZHEVXANCNFSM457RKLGQ .

hkjpotato commented 2 years ago

@slimandslam if I understand it correctly, you want to inject a credentials you get from a separate cognito identity pool? If you are using amplify to setup the identity pool, then the unauth credentials should be managed internally by the amplify, so you should not need to call the direct cognito commands.

ventocis commented 2 years ago

@slimandslam I am having the same issue. It sounds like you may have figured out how to attach the credentials using the methods below? Where are you getting these methods? I didn't see them in the Auth documentation. Thanks!

To create the temporary credentials, I had to use three API calls: GetIdCommand() GetOpenIdTokenCommand() AssumeRoleWithWebIdentityCommand()

The last call required the Cognito UNauthenticated role ARN.

slimandslam commented 2 years ago

I believe that one of the maintainers of the AWS SDK for JavaScript V3 API created an example somewhere (after I asked him about it) but I don't recall where.

The code below is what I use in React, but I assume it's pretty generic AWS SDK for JS V3 code.......

Note that there are examples of how to do this using AWS SDK for JS V2. (VERSION TWO), but not V3. I see no way to do this using AWS Amplify for JS because there is no way to use temporary credentials when making API calls. I'm specifically wanting to use temp credentials so that unauthorized visitors can do some bookkeeping API calls using the UNAUTH_ROLE_ARN. I wouldn't waste my time speculating on how to do this unless you have a verified working example. :-)

Required imports:

import { CognitoIdentityClient, GetIdCommand, GetOpenIdTokenCommand} from "@aws-sdk/client-cognito-identity";
import { STSClient, AssumeRoleWithWebIdentityCommand} from "@aws-sdk/client-sts";
import { fromCognitoIdentityPool } from "@aws-sdk/credential-provider-cognito-identity";

The basic flow:

const stsclnt = new STSClient({ region: "us-west-2" });
 const cognitoIdentityClient = new CognitoIdentityClient({
    region: "us-west-2",
  });
 const cogident = new CognitoIdentityClient({
    region: "us-west-2",
    credentials: fromCognitoIdentityPool({
      client: cognitoIdentityClient,
      identityPoolId: config.cognito.IDENTITY_POOL_ID,
    }),
  });
var GetParams = {
    IdentityPoolId: config.cognito.IDENTITY_POOL_ID,
  };

 try {
    const data = await cogident.send(new GetIdCommand(GetParams));
    const OpenParams = { IdentityId: data.IdentityId };
    const moredata = await cogident.send(new GetOpenIdTokenCommand(OpenParams));
    const credParams = {
      RoleArn: config.UNAUTH_ROLE_ARN,
      RoleSessionName: "websesh",
      WebIdentityToken: moredata.Token,
    };
    const moredata2 = await stsclnt.send(
      new AssumeRoleWithWebIdentityCommand(credParams)
    );
  return moredata2;  // AccessKeyId, SecretAccessKey, SessionToken
} catch..........