aws-amplify / amplify-swift

A declarative library for application development using cloud services.
Apache License 2.0
460 stars 198 forks source link

Provide custom AWS Credentials for storage category #3917

Open oleg-moseyko opened 1 week ago

oleg-moseyko commented 1 week ago

Is your feature request related to a problem? Please describe.

I would like to upload file to bucket but I can't figure out how to set up Amplify configure by accessKeyId/secretKey with sessionToken which i get from my server:

let tempCredentials = AWSCredentialIdentity(
  accessKey: "accessKeyId",
  secret: "secretKey",
  expiration: nil,
  sessionToken: "sessionToken"
) 
edisooon commented 1 week ago

Hi @oleg-moseyko, thank you for using Amplify! Amplify Storage library manages the tokens retrieved from Cognito to interact with S3 buckets. You could follow our official documentation to Set up Storage. And if you haven't done yet, you could follow the guide in Quick Start to create Amplify Backend with Authentication. Let me know if you have any other questions! šŸ˜

oleg-moseyko commented 1 week ago

Hi @edisooon thank you for sending me the links that I have read many times before And could you answer the specific question that I asked?

github-actions[bot] commented 1 week ago

This has been identified as a feature request. If this feature is important to you, we strongly encourage you to give a šŸ‘ reaction on the request. This helps us prioritize new features most important to you. Thank you!

harsh62 commented 1 week ago

@oleg-moseyko Providing custom AWS Credentials is currently not supported in the Storage category.

lon9man commented 1 week ago

@edisooon, @harsh62

.. my current state is like on harsh62-avatar.

so in 21 century basic developer with basic size mobile application and basic backend to implement basic upload to S3 should:

is this way suggested as the best and simplest? thanks!

harsh62 commented 1 week ago

@lon9man

From an Amplify perspective, this is considered as an advanced and not very common use case. This is the first feature request we have received for providing custom credentials to storage category.

You could still use the AWS SDK for Swift or Kotlin to achieve your use case, just not using Amplify.

Ideal use case would be:

  1. Federate into the Identity Pools using your custom backend as a provider. You would need to add your backend as a custom provider in identity pools.
  2. Once you have setup the identity pool correctly, use the Storage API without any customization.
oleg-moseyko commented 1 week ago

@harsh62 i want to implement multipart upload with progress monitoring

  1. AWS SDK (aws-swift) does not support multipart upload with progress monitoring
  2. AWS SDK (aws-ios) support multipart upload with progress monitoring - BUT is deprecated - if i understand correctly
  3. aws-amplify - support multipart upload with progress monitoring - BUT custom AWS Credentials is currently not supported

how to live with this fucking nonsense? could you provide example for: Federate into the Identity Pools using your custom backend as a provider. what is wrong?

       let authConfiguration = AuthCategoryConfiguration(plugins: [
            "awsCognitoAuthPlugin": [
                "UserAgent": "aws-amplify/cli",
                "Version": "0.1.0",
                "IdentityManager": [
                    "Default": []
                ],
                "CredentialsProvider": [
                    "CognitoIdentity": [
                        "Default": [
                            "PoolId": "us-east-1:ca441e53-XXXXX",
                            "Region": "us-east-1"
                        ]
                    ]
                ],
            ]
        ]
        )
        let configuration = AmplifyConfiguration(auth: authConfiguration)
        let authPlugin = AWSCognitoAuthPlugin()
        let storagePlugin = AWSS3StoragePlugin()

        try Amplify.add(plugin: authPlugin)
        try Amplify.add(plugin: storagePlugin)
        try Amplify.configure(configuration)
harsh62 commented 1 week ago

@oleg-moseyko ,

Thanks for raising this concern. I understand the frustration when navigating through the complexities of AWS Services and available features. Letā€™s address your requirements step-by-step. Specifically, Iā€™ll focus on federating into Cognito Identity Pools using a custom backend and developer-provided identity IDs.

I think the following image best reflects your architecture and probably how you should setup everything to access backend resources securely.

image Reference

Using Developer Authenticated Identities

To implement developer-authenticated identities, the flow involves:

  1. Authenticating the user via your backend.
  2. Using the backend to call GetOpenIdTokenForDeveloperIdentity to generate an identity ID and token.
  3. Using these in your frontend to federate into Cognito Identity Pools with the federateToIdentityPool API.

Below are examples for the backend (in PHP) and the frontend.


Backend Example (PHP)

Using the AWS SDK for PHP, your backend can generate tokens by calling GetOpenIdTokenForDeveloperIdentity. Hereā€™s how it looks:

My PHP skills are not very polished, but this is what I could come up with a little help from Amazon Q

<?php

require 'vendor/autoload.php';

use Aws\CognitoIdentity\CognitoIdentityClient;
use Aws\Exception\AwsException;

class CognitoService
{
    private $client;

    public function __construct($region)
    {
        $this->client = new CognitoIdentityClient([
            'version' => 'latest',
            'region'  => $region,
        ]);
    }

    public function getIdentityToken($identityPoolId, $providerName, $userId)
    {
        try {
            $result = $this->client->getOpenIdTokenForDeveloperIdentity([
                'IdentityPoolId' => $identityPoolId,
                'Logins'         => [
                    $providerName => $userId,
                ],
                'TokenDuration'  => 86400, // Token duration in seconds (optional)
            ]);

            return [
                'identityId' => $result['IdentityId'],
                'token'      => $result['Token'],
            ];
        } catch (AwsException $e) {
            throw new Exception('Error generating token: ' . $e->getMessage());
        }
    }
}

// Usage
$cognitoService = new CognitoService('us-east-1');
$identityPoolId = 'your-identity-pool-id';
$providerName = 'your-auth-provider-name';
$userId = 'unique-user-identifier';

try {
    $credentials = $cognitoService->getIdentityToken($identityPoolId, $providerName, $userId);
} catch (Exception $e) {
    echo 'Error: ' . $e->getMessage();
}

This script:

  1. Initializes the AWS Cognito Identity client.
  2. Calls GetOpenIdTokenForDeveloperIdentity to get the IdentityId and Token.
  3. Returns these values, which youā€™ll send securely to your frontend.

Frontend Example (Swift)

On the frontend, use the federateToIdentityPool API with the identityId and token obtained from your backend. Hereā€™s the Swift implementation:

import Amplify

func federateToIdentityPoolsUsingCustomIdentityId(identityId: String, token: String) async throws {
    guard let authCognitoPlugin = try Amplify.Auth.getPlugin(for: "awsCognitoAuthPlugin") as? AWSCognitoAuthPlugin else {
        fatalError("Unable to get the Auth plugin")
    }

    do {
        let result = try await authCognitoPlugin.federateToIdentityPool(
            withProviderToken: token,
            for: .custom("your-auth-provider-name"),
            options: .init(developerProvidedIdentityID: identityId)
        )
        print("Federation successful with result: \(result)")
    } catch {
        print("Failed to federate to identity pools with error: \(error)")
    }
}

Storage

Once you have completed the above steps, you should be able to use the Storage without any additional configuration, as Amplify under the hood will use the developer provided identity id and token to generate AWS Credentials on your behalf.


Key Considerations

  1. Token Refresh: Amplify does not auto-refresh federated tokens. Youā€™ll need to handle renewal in your app.
  2. Role Permissions: Set up your Identity Pool roles with least-privilege permissions to avoid over-permissioning.

Further Reading

For more details on Developer Authenticated Identities and how they work, check out this blog:
Understanding Amazon Cognito Authentication - Part 2.

If you run into specific issues during implementation, feel free to share more detailsā€”Iā€™m happy to help!


Hopefully this should enough to get you over the finish line. šŸ¤ž

oleg-moseyko commented 1 week ago

Hi @harsh62 finally i got something like a normal answer from support thanks i will investigate