Skip to content
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

Amplify Gen2 Flutter REST API #5252

Open
2 of 14 tasks
mateuszboryn opened this issue Aug 8, 2024 · 2 comments
Open
2 of 14 tasks

Amplify Gen2 Flutter REST API #5252

mateuszboryn opened this issue Aug 8, 2024 · 2 comments
Labels
feature-parity A request for a feature that is fully or partially available on another platform (JS, iOS, Android) feature-request A request for a new feature or an enhancement to an existing API or category. REST API Issues related to the API (REST) Category

Comments

@mateuszboryn
Copy link

mateuszboryn commented Aug 8, 2024

Description

I can't see an example of Amplify Gen2 Flutter REST API.
There is one for React (https://docs.amplify.aws/react/build-a-backend/add-aws-services/rest-api/set-up-rest-api/), however whatever I try for Flutter, it doesn't work.
Could you please provide some working example of:

  1. REST API Gateway CDK
  2. AND Dart code that invokes REST endpoint
  3. AND authorization using Cognito User pool for that endpoint

Categories

  • Analytics
  • API (REST)
  • API (GraphQL)
  • Auth
  • Authenticator
  • DataStore
  • Notifications (Push)
  • Storage

Steps to Reproduce

There's documentation for React (https://docs.amplify.aws/react/build-a-backend/add-aws-services/rest-api/set-up-rest-api/), but I can't find one for flutter.
I tried to adapt existing example from React to Flutter, however I can't get requests authorized.

// backend.ts
// all the same as https://docs.amplify.aws/react/build-a-backend/add-aws-services/rest-api/set-up-rest-api/
// except for outputs, which is here, adjusted to what Flutter's Gen2 configure() expects:

// add outputs to the configuration file
backend.addOutput({
    custom: {
        rest_api: {
            [myRestApi.restApiName]: {
                aws_region: Stack.of(myRestApi).region,
                url: myRestApi.url,
                authorization_type: "AMAZON_COGNITO_USER_POOLS",
            },
        },
    }
});
// in _configureAmplify()
Map decodedAmplifyConfig = json.decode(amplifyConfig);
var newConfig = {};
newConfig.addAll(decodedAmplifyConfig);
newConfig.addAll(decodedAmplifyConfig["custom"]);
await Amplify.configure(json.encode(newConfig));
// call the API
try {
      final restOperation = Amplify.API.post(
        'cognito-auth-path',
        body: HttpPayload.json({'name': 'Mow the lawn'}),
      );
      final response = await restOperation.response;
      print('POST call succeeded');
      print(response.decodeBody());
    } on ApiException catch (e) {
      print('POST call failed: $e');
    }

The above gives 401

{"message":"Unauthorized"}

Screenshots

No response

Platforms

  • iOS
  • Android
  • Web
  • macOS
  • Windows
  • Linux

Flutter Version

3.22.3

Amplify Flutter Version

2.3.0

Deployment Method

AWS CDK

Schema

No response

@tyllark
Copy link
Member

tyllark commented Aug 9, 2024

Hi @mateuszboryn thank you for opening this request. I'm going to mark this as a feature request for REST API support in Gen2.

In the meantime can you you try updating your amplify config Json like in this example

final json = jsonDecode(amplifyConfig);

// ignore: avoid_dynamic_calls
json['rest_api'] = {'multiAuthRest': json['custom']['multiAuthRest']};
final configString = jsonEncode(json);

await Amplify.configure(configString);

Let us know if this resolves your issue and please note that this is not an officially supported work around and could break in future versions, but we will let you know when we have an official implementation.

@tyllark tyllark assigned tyllark and unassigned tyllark Aug 9, 2024
@tyllark tyllark added REST API Issues related to the API (REST) Category feature-parity A request for a feature that is fully or partially available on another platform (JS, iOS, Android) pending-community-response Pending response from the issue opener or other community members labels Aug 9, 2024
@mateuszboryn
Copy link
Author

Thank you @tyllark for prompt response and the example provided.

  • It helped me to get IAM auth REST API working.
  • However, I'm missing AMAZON_COGNITO_USER_POOLS REST API (I have a strict requirement to avoid AWS access key and secret access key in the REST API).

The example you linked has name suggesting it is multiAuthRest. I searched the repo for multiAuthRest and the only resources created that I found are using IAM, and not COGNITO USER POOL.

With that example I got API Gateway to have routes with AWS_IAM authorizer. I'm expecting to have Cognito User Pool authorizer instead.

Below is the code that is much closer to what I expect with some comments on which settings fail.

// create a new REST API
const myRestApi = new RestApi(apiStack, "RestApi", {
    restApiName: "multiAuthRest",
    deploy: true,
    deployOptions: {
        stageName: "dev",
    },
    defaultCorsPreflightOptions: {
        allowOrigins: Cors.ALL_ORIGINS, // Restrict this to domains you trust
        allowMethods: Cors.ALL_METHODS, // Specify only the methods you need to allow
        allowHeaders: Cors.DEFAULT_HEADERS, // Specify only the headers you need to allow
    },
});

// create a new Lambda integration
const lambdaIntegration = new LambdaIntegration(
    backend.addDeviceFunction.resources.lambda
);

// const cognitoAuth = new CognitoUserPoolsAuthorizer(apiStack, "CognitoAuth", {    // uncomment only for authorizationType: AuthorizationType.COGNITO in resource below
//     cognitoUserPools: [backend.auth.resources.userPool],
// });

// create a new resource path with IAM authorization
const itemsPath = myRestApi.root.addResource("items", {
    defaultMethodOptions: {
        authorizationType: AuthorizationType.IAM,    // works, but relies on AWS Access key and secret access key.
        // authorizationType: AuthorizationType.COGNITO, authorizer: cognitoAuth,      // fails with 401 {"message":"Unauthorized"}
    },
});

// add methods you would like to create to the resource path
itemsPath.addMethod("ANY", lambdaIntegration);

// add a proxy resource path to the API
itemsPath.addProxy({
    anyMethod: true,
    defaultIntegration: lambdaIntegration,
});

const apiRestPolicy = new Policy(apiStack, "RestApiPolicy", {
    statements: [
        new PolicyStatement({
            actions: ["execute-api:Invoke"],
            resources: [
                `${myRestApi.arnForExecuteApi("*", "/items", "dev")}`,
                `${myRestApi.arnForExecuteApi("*", "/items/*", "dev")}`,
            ],
        }),
    ],
});

// attach the policy to the authenticated and unauthenticated IAM roles
backend.auth.resources.authenticatedUserIamRole.attachInlinePolicy(
    apiRestPolicy
);

// add outputs to the configuration file
backend.addOutput({
    custom: {
        rest_api: {
            [myRestApi.restApiName]: {
                url: myRestApi.url.replace(/\/+$/, ""),
                aws_region: Stack.of(myRestApi).region,
                authorization_type: AuthorizationType.IAM,       // works, but relies on AWS Access key and secret access key.


                // authorization_type: AuthorizationType.COGNITO, this gives error (apparently, string is not recognized in dart code mappings):
                // E/flutter ( 5190): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: ConfigurationError {
                // E/flutter ( 5190):   "message": "The provided configuration can not be decoded to AmplifyOutputs or AmplifyConfig. Check underlyingException.",
                // E/flutter ( 5190):   "recoverySuggestion": "If using Amplify Gen 2 ensure that the json string can be decoded to AmplifyOutputs type. If using Amplify Gen 1 ensure that the json string can be decoded to AmplifyConfig type.",
                // E/flutter ( 5190):   "underlyingException": "CheckedFromJsonException\nCould not create `AuthConfig`.\nThere is a problem with \"plugins\".\nNull is not a Map"
                // E/flutter ( 5190): }
                // E/flutter ( 5190): #0      AmplifyClass._parseJsonConfig (package:amplify_core/src/amplify_class.dart:151:9)
                // E/flutter ( 5190): #1      AmplifyClass.configure (package:amplify_core/src/amplify_class.dart:117:24)
                // E/flutter ( 5190): #2      _MyApp._configureAmplify (package:tta_user_app/main.dart:100:21)
                // E/flutter ( 5190): <asynchronous suspension>

                // authorization_type: "AMAZON_COGNITO_USER_POOLS",     // fails with 401 {"message":"Unauthorized"}
            },
        }
    }
});

@Jordan-Nelson Jordan-Nelson added the feature-request A request for a new feature or an enhancement to an existing API or category. label Aug 16, 2024
@NikaHsn NikaHsn removed the pending-community-response Pending response from the issue opener or other community members label Aug 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-parity A request for a feature that is fully or partially available on another platform (JS, iOS, Android) feature-request A request for a new feature or an enhancement to an existing API or category. REST API Issues related to the API (REST) Category
Projects
None yet
Development

No branches or pull requests

4 participants