Giter Club home page Giter Club logo

aws-sdk-net-extensions-cognito's Introduction

.NET on AWS Banner

Amazon Cognito Authentication Extension Library

nuget

Amazon.Extensions.CognitoAuthentication simplifies the authentication process of Amazon Cognito User Pools for .NET developers.

It allows you to use various authentication methods for Amazon Cognito User Pools with only a few short method calls, and makes the process intuitive.

Learn more about Amazon Cognito User Pools.

This library targets the .NET Standard 2.0 and introduces the following dependencies:

Getting Started

To take advantage of this library, set up an AWS account and install the AWS SDK for .NET as described in Getting Started with the AWS SDK for .NET.

While this library is in development, you will need to build it manually.

Create a new project in Visual Studio and add the Amazon Cognito Authentication Extension Library as a reference to the project.

Using the library to make calls to the Amazon Cognito Identity Provider API from the AWS SDK for .NET is as simple as creating the necessary CognitoAuthentication objects and calling the appropriate AmazonCognitoIdentityProviderClient methods. The principal Amazon Cognito authentication objects are:

  • CognitoUserPool objects store information about a user pool, including the poolID, clientID, and other pool attributes.
  • CognitoUser objects contain a user’s username, the pool they are associated with, session information, and other user properties.
  • CognitoDevice objects include device information, such as the device key.

Authenticating with Secure Remote Protocol (SRP)

Instead of implementing hundreds of lines of cryptographic methods yourself, you now only need to create the necessary AmazonCognitoIdentityProviderClient, CognitoUserPool, CognitoUser, and InitiateSrpAuthRequest objects and then call StartWithSrpAuthAsync:

using Amazon.Runtime;
using Amazon.CognitoIdentityProvider;
using Amazon.Extensions.CognitoAuthentication;

public async void AuthenticateWithSrpAsync()
{
    var provider = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials(), FallbackRegionFactory.GetRegionEndpoint());
    var userPool = new CognitoUserPool("poolID", "clientID", provider);
    var user = new CognitoUser("username", "clientID", userPool, provider);

    var password = "userPassword";

    AuthFlowResponse authResponse = await user.StartWithSrpAuthAsync(new InitiateSrpAuthRequest()
    {
        Password = password
    }).ConfigureAwait(false);
}

The AuthenticationResult property of the AuthFlowResponse object contains the user’s session tokens if the user was successfully authenticated. If more challenge responses are required, this field is null and the ChallengeName property describes the next challenge, such as multi-factor authentication. You would then call the appropriate method to continue the authentication flow.

Authenticating with Multiple Forms of Authentication

Continuing the authentication flow with challenges, such as with NewPasswordRequired and Multi-Factor Authentication (MFA), is simpler as well.

The following code shows one way to check the challenge type and get appropriate responses for MFA and NewPasswordRequired challenges. This processing might be necessary as the authentication flow proceeds, depending on the properties of the AuthFlowResponse object that was retrieved earlier.

while (authResponse.AuthenticationResult == null)
{
    if (authResponse.ChallengeName == ChallengeNameType.NEW_PASSWORD_REQUIRED)
    {
        Console.WriteLine("Enter your desired new password:");
        string newPassword = Console.ReadLine();

        authResponse = 
            await user.RespondToNewPasswordRequiredAsync(new RespondToNewPasswordRequiredRequest()
            {
                SessionID = authResponse.SessionID,
                NewPassword = newPassword
            }).ConfigureAwait(false);
    }
    else if (authResponse.ChallengeName == ChallengeNameType.SMS_MFA)
    {
        Console.WriteLine("Enter the MFA Code sent to your device:");
        string mfaCode = Console.ReadLine();

        authResponse = await user.RespondToSmsMfaAuthAsync(new RespondToSmsMfaRequest()
        {
                SessionID = authResponse.SessionID,
                MfaCode = mfaCode
        }).ConfigureAwait(false);
        }
        else
        {
            Console.WriteLine("Unrecognized authentication challenge.");
            break;
        }
}

Learn more about Amazon Cognito User Pool Authentication Flow.

Authenticating with Different Levels of Authentication

After a user is authenticated by using the Amazon Cognito Authentication Extension Library, you can then allow them to access specific AWS resources.

To allow users to access specific AWS resources, you must create an identity pool through the Amazon Cognito Federated Identities console.

You can also specify different roles for both unauthenticated and authenticated users so that they can access different resources. These roles can be changed in the IAM console where you can add or remove permissions in the Action field of the role’s attached policy. Then, using the appropriate identity pool, user pool, and Amazon Cognito user information, calls can be made to different AWS resources.

The following code shows how a user, who was authenticated with SRP, can access various S3 buckets as permitted by the associated identity pool’s role.

using Amazon;
using Amazon.Runtime;
using Amazon.S3;
using Amazon.S3.Model;
using Amazon.CognitoIdentity;
using Amazon.CognitoIdentityProvider;
using Amazon.Extensions.CognitoAuthentication;

public async void GetS3BucketsAsync()
{
    var provider = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials(),
                                                            FallbackRegionFactory.GetRegionEndpoint());
    var userPool = new CognitoUserPool("poolID", "clientID", provider);
    var user = new CognitoUser("username", "clientID", userPool, provider);

    var password = "userPassword";

    await user.StartWithSrpAuthAsync(new InitiateSrpAuthRequest()
    {
        Password = password
    }).ConfigureAwait(false);

    var credentials = 
        user.GetCognitoAWSCredentials("identityPoolID", RegionEndpoint.<YourIdentityPoolRegion>);

    using (var client = new AmazonS3Client(credentials))
    {
        ListBucketsResponse response = 
            await client.ListBucketsAsync(new ListBucketsRequest()).ConfigureAwait(false);

        foreach (S3Bucket bucket in response.Buckets)
        {
            Console.WriteLine(bucket.BucketName);
        }
    }
}

Authenticating using a Refresh Token from a Previous Session

Access and ID tokens provided by Cognito are only valid for one hour but the refresh token can be configured to be valid for much longer. Below is an example of how to retrieve new Access and ID tokens using a refresh token which is still valid.

See here to learn more about using the tokens returned by Amazon Cognito.

using Amazon;
using Amazon.Runtime;
using Amazon.CognitoIdentity;
using Amazon.CognitoIdentityProvider;
using Amazon.Extensions.CognitoAuthentication;

public async Task GetCredsFromRefreshAsync(string refreshToken, string deviceKey)
{
    using var provider = new AmazonCognitoIdentityProviderClient();
    var userPool = new CognitoUserPool("poolID", "clientID", provider);

    var user = new CognitoUser("username", "clientID", userPool, provider, "clientSecret")
    {
        SessionTokens = new CognitoUserSession(null, null, refreshToken, DateTime.UtcNow, DateTime.UtcNow.AddHours(1))
    };

    // If the user pool is configured to track and remember user devices, it must be attached to the user before initiating the flow:
    // user.Device = new CognitoDevice(new DeviceType { DeviceKey = deviceKey }, user);

    var authResponse = await user.StartWithRefreshTokenAuthAsync(new InitiateRefreshTokenAuthRequest
    {
        AuthFlowType = AuthFlowType.REFRESH_TOKEN_AUTH
    });
}

Other Forms of Authentication

In addition to SRP, NewPasswordRequired, MFA and Refresh the Amazon Cognito Authentication Extension Library offers an easier authentication flow for the following:

  • Custom – Begins with a call to StartWithCustomAuthAsync(InitiateCustomAuthRequest customRequest)
  • AdminNoSRP – Begins with a call to StartWithAdminNoSrpAuth(InitiateAdminNoSrpAuthRequest adminAuthRequest)

Getting Help

We use the GitHub issues for tracking bugs and feature requests and have limited bandwidth to address them.

If you think you may have found a bug, please open an issue

Contributing

We welcome community contributions and pull requests. See CONTRIBUTING for information on how to set up a development environment and submit code.

Additional Resources

AWS .NET GitHub Home Page
GitHub home for .NET development on AWS. You'll find libraries, tools, and resources to help you build .NET applications and services on AWS.

AWS Developer Center - Explore .NET on AWS
Find .NET code samples, step-by-step guides, videos, blog content, tools, and information about live events all in one place.

AWS Developer Blog - .NET
Come and see what .NET developers at AWS are up to! Learn about new .NET software announcements, guides, and how-to's.

@dotnetonaws Follow us on twitter!

License

Libraries in this repository are licensed under the Apache 2.0 License.

See LICENSE and NOTICE for more information.

aws-sdk-net-extensions-cognito's People

Contributors

96malhar avatar ashishdhingra avatar ashovlin avatar ca0abinary avatar costleya avatar dmitryproskurin avatar dscpinheiro avatar gabrielhare avatar ganeshnj avatar hyandell avatar itamaram avatar joshongithub avatar kellertk avatar konectech avatar ngl321 avatar normj avatar paul-b-aws avatar peterrsongg avatar petrenslavik avatar philasmar avatar ppittle avatar somayab avatar srutig avatar swensorm avatar theobalestra avatar vellozzi avatar wajahataliabid avatar walshj19 avatar willsmith9182 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aws-sdk-net-extensions-cognito's Issues

Error assigning valid device_key to a CognitoDevice and applying it to CongitoUser.Device prior to calling StartWithSrpAuthAsync (Device Tracking Enabled)

I can't seem to figure out how to properly add a newly tracked device to a CognitoUser.Device prior to logging in, so the login is tracked for that device key.

Here is the general flow, as an overview:

  • User logs into cognito using StartWithSrpAuthAsync without a device key, as the application is a new device. (SUCCESS)
var userPool = new CognitoUserPool(_settings.UserPoolId, _settings.ClientId, _cognitoClient);
var user = new CognitoUser(userName, _settings.ClientId, userPool, _cognitoClient);
var authResponse = await user.StartWithSrpAuthAsync(new InitiateSrpAuthRequest()
{
      Password = password
}).ConfigureAwait(false);

2: The AuthenticationResult object within the response contains a NewDeviceMetadata object, which contains a new DeviceKey (CONFIRMED)

3: The application generates a salt and password verifier and passes it to Cognito, and receives a 200 response.

var confirmDeviceResponse = await ConfirmDeviceAsync(creds, new NewDeviceInfo
{
    GroupKey = authResponse.AuthenticationResult.NewDeviceMetadata.DeviceGroupKey,
    Key = authResponse.AuthenticationResult.NewDeviceMetadata.DeviceKey,
    Name = _settings.DeviceName
});

if (confirmDeviceResponse.HttpStatusCode != HttpStatusCode.OK)
{
    throw new Exception(JObject.FromObject(confirmDeviceResponse).ToString());
}
  1. First we save the now-tracked deviceKey to user settings for the application. As a test, we then try immediately refreshing the Cognito session, leveraging InitiateAuthAsync with a DEVICE_KEY AuthParameter and a REFRESH_TOKEN_AUTH AuthFlow:
var userPool = new CognitoUserPool(currentCreds.UserPoolId, currentCreds.ClientId, _cognitoClient);
var user = new CognitoUser(currentCreds.Username, currentCreds.ClientId, userPool, _cognitoClient)
{
     //we have to do this its a bug in the 'StartWithRefreshTokenAuthAsync' 
     //see article https://github.com/aws/aws-sdk-net/issues/844
     SessionTokens = new CognitoUserSession(
         currentCreds.UserPoolIdToken,
         currentCreds.UserPoolAccessToken,
         currentCreds.UserPoolRefreshToken,
         DateTime.Now,
         DateTime.Now.AddHours(1)
     )
};
 user.Device = new CognitoDevice(
     new DeviceType { DeviceKey = currentCreds.DeviceKey }, 
     user
);

var authResponse = await _cognitoClient.InitiateAuthAsync(new InitiateAuthRequest()
{
      AuthFlow = AuthFlowType.REFRESH_TOKEN_AUTH,
      ClientId = currentCreds.ClientId,
      AuthParameters = new Dictionary<string, string>()
      {
          { "USERNAME", currentCreds.Username },
          { "REFRESH_TOKEN", currentCreds.UserPoolRefreshToken },
          { "DEVICE_KEY",  currentCreds.DeviceKey }
       }
});

var newCreds = user.GetCognitoAWSCredentials(
       currentCreds.IdentityPoolId,
       Amazon.RegionEndpoint.USEast1
).GetCredentials();

5: Now, the next time we load the application, we use the device key that now exists:

var userPool = new CognitoUserPool(_settings.UserPoolId, _settings.ClientId, _cognitoClient);
var user = new CognitoUser(userName, _settings.ClientId, userPool, _cognitoClient);


//use existing device key if available
if (_settings.DeviceKey != string.Empty)
{
    var device = new CognitoDevice(new DeviceType
    {
        DeviceKey = _settings.DeviceKey
    }, user);
    user.Device = device;
}
var authResponse = await user.StartWithSrpAuthAsync(new InitiateSrpAuthRequest()
{
    Password = password
}).ConfigureAwait(false);

6: Observe error during StartWithSrpAuthAsync() from step 5:

Unhandled Exception: System.ArgumentException: An item with the same key has already been added. Key: DEVICE_KEY
   at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
   at Amazon.Extensions.CognitoAuthentication.CognitoUser.StartWithSrpAuthAsync(InitiateSrpAuthRequest srpRequest)

I've also tried calling the following after authenticating (for step 5), but receive the same error:

await user.Device.RememberThisDeviceAsync(); 
var authResponse = await user.StartWithSrpAuthAsync(new InitiateSrpAuthRequest()
{
    Password = password
}).ConfigureAwait(false);
//use existing device key if available
if (_settings.DeviceKey != string.Empty)
{
    var device = new CognitoDevice(new DeviceType
    {
        DeviceKey = _settings.DeviceKey
    }, user);
    user.Device = device;
    await user.Device.RememberThisDeviceAsync();
}

DeviceKey is being added twice to challenge request in CognitoUser.StartWithSrpAuthAsync

In CognitoUser.StartWithSrpAuthAsync DeviceKey is being added twice to challenge request causing "An item with the same key has already been added" exception

Expected Behavior

StartWithSrpAuthAsync with a DeviceKey does not throw an exception

Current Behavior

The DeviceKey is added to the challenge request in CreateSrpPasswordVerifierAuthRequest and then again in StartWithSrpAuthAsync, causing a "An item with the same key has already been added" exception

CognitoUser.StartWithSrpAuthAsync

bool challengeResponsesValid = challengeRequest != null && challengeRequest.ChallengeResponses != null;
bool deviceKeyValid = Device != null && !string.IsNullOrEmpty(Device.DeviceKey);

if (challengeResponsesValid && deviceKeyValid)
{
    challengeRequest.ChallengeResponses.Add(CognitoConstants.ChlgParamDeviceKey, Device.DeviceKey);
}

CognitoUser.CreateSrpPasswordVerifierAuthRequest

if (Device != null && !string.IsNullOrEmpty(Device.DeviceKey))
{
    srpAuthResponses.Add(CognitoConstants.ChlgParamDeviceKey, Device.DeviceKey);
}

Possible Solution

Only add DeviceKey once

Steps to Reproduce (for bugs)

Call StartWithSrpAuthAsync with a DeviceKey in the CognitoUser object

`CognitoAuthHelper.GetAssemblyFileVersion` Expensive CPU Wise

Describe the bug

We’ve noticed some issues with the AWS Cognito Dotnet Library in terms of performance. We were having some performance issues on our server, and upon investigation, every Cognito call that we make calls a function CognitoAuthHelper.GetAssemblyFileVersion that is rather expensive since it reads an Assembly to get the version and send it back to AWS for metrics.
As shown in the flame graph below, it’s taking around 77ms of CPU time, (which in the case of this endpoint we make 3 cognito calls, which accounts for 90%+ of the CPU time). It also reads it every single time we make a call instead of caching the version, which would stay unchanged if the process is never restarted.
Cognito Flame Graph

Expected Behavior

Not have a CPU expensive call everytime there is a Cognito Call

Current Behavior

Every Cognito API call causes a large block when attempting to read an assembly file

Reproduction Steps

Any call to Cognito SDK will cause the issue

Possible Solution

Disable the call to get the AssemblyFileVersion, or cache the version

Additional Information/Context

No response

AWS .NET SDK and/or Package version used

AWSSDK.Core v3.7.13.10

Targeted .NET Platform

.NET Core 3.1

Operating System and version

Windows Server 2019, Mac OS Ventura

CognitoUser.ListDevicesAsync() doesn't support returning pagination token.

Describe the feature

This feature request is specific for UserAuthentication.CognitoUser's ListDevicesAsync() method.

Current this method takes a limit (number of devices to return) and a continuation token (to presumable retrieve the next set of devices attached to a user). The limitation of the current implementation is, ListDevicesAsync() only returns the list of devices, it does not return the call's continuation token. Without the initial call to ListDevicesAsync()'s continuation token, it's not possible to get the next set of devices and subsequent calls.

Use Case

To retrieve a complete list of a user's devices, when the user has more than 60 (the maximum limit) devices.

Proposed Solution

No response

Other Information

No response

Acknowledgements

  • I may be able to implement this feature request
  • This feature might incur a breaking change

AWS .NET SDK and/or Package version used

Amazon.Extensions.CognitoAuthentication version 2.3.0

Targeted .NET Platform

netstandard2.0 netstandard2.1

Operating System and version

Windows 11

Issue using Refresh Token flow

I'm using the snippet from this flow and can successfully retrieve an access token and refresh token from the AuthenticationResult value, but upon saving the refresh token and putting it back through the aforementioned snippet I get Invalid Refresh Token as a response.

Am I missing some key AWS-side config setting here or something like that? Is the client secret required for refresh keys maybe? (there isn't one set currently)

This is using the SDK 3.7.57.0 and Extensions 2.21 in Unity

Cognito StartWithRefreshTokenAuthAsync incorrectly checks SessionTokens.ExpirationTime, fails with "User is not authenticated."

Expected Behavior

Invoking StartWithRefreshTokenAuthAsync on an instance of CognitoUser that had previously authenticated, but now has an expired access token should result in a new access token with an expiration date in the future.

Current Behavior

StartWithRefreshTokenAuthAsync throws the following exception:

Amazon.CognitoIdentityProvider.Model.NotAuthorizedException: User is not authenticated.
   at Amazon.Extensions.CognitoAuthentication.CognitoUser.EnsureUserAuthenticated()
   at Amazon.Extensions.CognitoAuthentication.CognitoUser.CreateRefreshTokenAuthRequest(AuthFlowType authFlowType)
   at Amazon.Extensions.CognitoAuthentication.CognitoUser.<StartWithRefreshTokenAuthAsync>d__82.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
... ommitted for brevity

Possible Solution

My workaround right now is to manually assign the user's SessionTokens to a new instance created with the existing tokens, but with an expiration time set in the future by an arbitrary amount seems to let it work around the check to see if the tokens are expired.

user.SessionTokens = new CognitoUserSession(
	user.SessionTokens.IdToken,
	user.SessionTokens.AccessToken,
	user.SessionTokens.RefreshToken,
	user.SessionTokens.IssuedTime,
	DateTime.Now.AddHours(1)
);
var response = await user.StartWithRefreshTokenAuthAsync(new InitiateRefreshTokenAuthRequest
{
	AuthFlowType = AuthFlowType.REFRESH_TOKEN
});

A real solution is probably just to remove the call to EnsureUserAuthenticated from the top of CreateRefreshTokenAuthRequest in CognitoUserAuthentication.cs.

private InitiateAuthRequest CreateRefreshTokenAuthRequest(AuthFlowType authFlowType)
{
	// This line is the one that I suggest be removed
	EnsureUserAuthenticated();

	if (authFlowType != AuthFlowType.REFRESH_TOKEN && authFlowType != AuthFlowType.REFRESH_TOKEN_AUTH)
	{
		throw new ArgumentException("authFlowType must be either \"REFRESH_TOKEN\" or \"REFRESH_TOKEN_AUTH\"", "authFlowType");
	}

Steps to Reproduce (for bugs)

Authenticate a cognito user via some variant of the following:

AmazonCognitoIdentityProviderClient provider = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials(), RegionEndpoint.USEast2);
CognitoUserPool userPool = new CognitoUserPool(Constants.UserPoolId, Constants.ClientId, provider);
user = new Amazon.Extensions.CognitoAuthentication.CognitoUser(username, Constants.ClientId, userPool, provider);

await user.StartWithSrpAuthAsync(new InitiateSrpAuthRequest()
{
	Password = password
});

Wait an hour for the access token to expire.

Attempt to refresh the user:

await user.StartWithRefreshTokenAuthAsync(new InitiateRefreshTokenAuthRequest
{
	AuthFlowType = AuthFlowType.REFRESH_TOKEN
});

Observe that it throws:

Amazon.CognitoIdentityProvider.Model.NotAuthorizedException: User is not authenticated.

Context

I need a cognito user that is as long-lived as it would be on any other client (ex. our web client handles refreshes just fine, allowing multi-hour sessions). If I log in to the desktop client created using this library, and then just leave that client running for an hour all API calls start failing with 401s. Refreshing the user when that happens throws the aforementioned exception, rather than resulting in a valid cognito user with a new access token.

It's worth pointing out that even with a solution to this problem (or a workaround related to messing with expiration time on the tokens object), I still run into another issue related to the refresh action clearing the refresh token instead of leaving it alone or updating it. This bug has already been mentioned, just worth pointing out that fixing this bug and that bug together are required for a real refresh system:
https://github.com/aws/aws-sdk-net/issues/778

Your Environment

  • AWSSDK.Core version used: 3.3.19.0
  • Service assembly and version used:
  • Operating System and version: Windows 10 1709 (OS Build 19299.192)
  • Visual Studio version: Community 2017 15.5.4
  • Targeted .NET platform: Core 2.1

.NET Core Info

  • .NET Core version used for development: 2.1.4
  • .NET Core version installed in the environment where application runs: 2.1.4
  • Output of dotnet --info:
.NET Command Line Tools (2.1.4)

Product Information:
 Version:            2.1.4
 Commit SHA-1 hash:  5e8add2190

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.16299
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\2.1.4\

Microsoft .NET Core Shared Framework Host

  Version  : 2.0.5
  Build    : 17373eb129b3b05aa18ece963f8795d65ef8ea54
  • Contents of project.json/project.csproj:
    project.json:
{
  "dependencies": {
    "AWSSDK.CognitoIdentity": "3.3.2.17",
    "AWSSDK.CognitoIdentityProvider": "3.3.8",
    "AWSSDK.Extensions.CognitoAuthentication": "0.9.1",
    "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2",
    "Microsoft.Toolkit.Uwp.Notifications": "2.1.0",
    "NETStandard.Library": "2.0.1",
    "Newtonsoft.Json": "10.0.3",
    "QueryString.NET": "1.0.0",
    "System.Net.Http": "4.3.3",
    "System.Threading": "4.3.0",
    "System.Threading.Tasks": "4.3.0",
    "System.Threading.Timer": "4.3.0",
    "Xamarin.Forms": "2.5.0.121934"
  },
  "frameworks": {
    "uap10.0.16299": {}
  },
  "runtimes": {
    "win10-arm": {},
    "win10-arm-aot": {},
    "win10-x86": {},
    "win10-x86-aot": {},
    "win10-x64": {},
    "win10-x64-aot": {}
  }
}

SDPNativeClient.UWP.csproj:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
    <ProjectGuid>{FD00B0CC-4454-440C-9F0E-00BFC3E99032}</ProjectGuid>
    <OutputType>AppContainerExe</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>SDPNativeClient.UWP</RootNamespace>
    <AssemblyName>SDPNativeClient.UWP</AssemblyName>
    <DefaultLanguage>en-US</DefaultLanguage>
    <TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
    <TargetPlatformVersion>10.0.16299.0</TargetPlatformVersion>
    <TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
    <MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
    <EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile>
    <FileAlignment>512</FileAlignment>
    <ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
    <PackageCertificateKeyFile>impulse.pfx</PackageCertificateKeyFile>
    <RuntimeIdentifiers>win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot</RuntimeIdentifiers>
    <AppxAutoIncrementPackageRevision>True</AppxAutoIncrementPackageRevision>
    <AppxBundle>Always</AppxBundle>
    <AppxBundlePlatforms>x64</AppxBundlePlatforms>
    <PackageCertificateThumbprint>5B78E478072A4493A14DEF9F91A15E82DE7E1127</PackageCertificateThumbprint>
    <AppxSymbolPackageEnabled>False</AppxSymbolPackageEnabled>
    <AppxPackageDir>C:\Users\IEUser\Desktop\installables\</AppxPackageDir>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
    <DebugSymbols>true</DebugSymbols>
    <OutputPath>bin\ARM\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
    <NoWarn>;2008</NoWarn>
    <DebugType>full</DebugType>
    <PlatformTarget>ARM</PlatformTarget>
    <UseVSHostingProcess>false</UseVSHostingProcess>
    <ErrorReport>prompt</ErrorReport>
    <Prefer32Bit>true</Prefer32Bit>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
    <OutputPath>bin\ARM\Release\</OutputPath>
    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
    <Optimize>true</Optimize>
    <NoWarn>;2008</NoWarn>
    <DebugType>pdbonly</DebugType>
    <PlatformTarget>ARM</PlatformTarget>
    <UseVSHostingProcess>false</UseVSHostingProcess>
    <ErrorReport>prompt</ErrorReport>
    <Prefer32Bit>true</Prefer32Bit>
    <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
    <DebugSymbols>true</DebugSymbols>
    <OutputPath>bin\x64\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
    <NoWarn>;2008</NoWarn>
    <DebugType>full</DebugType>
    <PlatformTarget>x64</PlatformTarget>
    <UseVSHostingProcess>false</UseVSHostingProcess>
    <ErrorReport>prompt</ErrorReport>
    <Prefer32Bit>true</Prefer32Bit>
    <UseDotNetNativeToolchain>false</UseDotNetNativeToolchain>
    <Optimize>false</Optimize>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
    <OutputPath>bin\x64\Release\</OutputPath>
    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
    <Optimize>true</Optimize>
    <NoWarn>;2008</NoWarn>
    <DebugType>pdbonly</DebugType>
    <PlatformTarget>x64</PlatformTarget>
    <UseVSHostingProcess>false</UseVSHostingProcess>
    <ErrorReport>prompt</ErrorReport>
    <Prefer32Bit>true</Prefer32Bit>
    <UseDotNetNativeToolchain>false</UseDotNetNativeToolchain>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
    <DebugSymbols>true</DebugSymbols>
    <OutputPath>bin\x86\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
    <NoWarn>;2008</NoWarn>
    <DebugType>full</DebugType>
    <PlatformTarget>x86</PlatformTarget>
    <UseVSHostingProcess>false</UseVSHostingProcess>
    <ErrorReport>prompt</ErrorReport>
    <Prefer32Bit>true</Prefer32Bit>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
    <OutputPath>bin\x86\Release\</OutputPath>
    <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
    <Optimize>true</Optimize>
    <NoWarn>;2008</NoWarn>
    <DebugType>pdbonly</DebugType>
    <PlatformTarget>x86</PlatformTarget>
    <UseVSHostingProcess>false</UseVSHostingProcess>
    <ErrorReport>prompt</ErrorReport>
    <Prefer32Bit>true</Prefer32Bit>
    <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="API\IPCService.cs" />
    <Compile Include="Platform\VPNService.cs" />
    <Compile Include="App.xaml.cs">
      <DependentUpon>App.xaml</DependentUpon>
    </Compile>
    <Compile Include="MainPage.xaml.cs">
      <DependentUpon>MainPage.xaml</DependentUpon>
    </Compile>
    <Compile Include="OpenAppService.cs" />
    <Compile Include="Platform\PlatformEffectUWP.cs" />
    <Compile Include="Platform\PlatformReplaceAppTitle.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
    <Compile Include="Toaster.cs" />
  </ItemGroup>
  <ItemGroup>
    <AppxManifest Include="Package.appxmanifest">
      <SubType>Designer</SubType>
    </AppxManifest>
    <None Include="impulse.pfx">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Include="project.json" />
    <None Include="SDPNativeClient.UWP_TemporaryKey.pfx" />
  </ItemGroup>
  <ItemGroup>
    <Content Include="app_icon.png" />
    <Content Include="Assets\Square44x44Logo.targetsize-16.png" />
    <Content Include="Assets\Square44x44Logo.targetsize-24.png" />
    <Content Include="Assets\Square44x44Logo.targetsize-256.png" />
    <Content Include="Assets\Square44x44Logo.targetsize-32.png" />
    <Content Include="Assets\Square44x44Logo.targetsize-48.png" />
    <Content Include="Bundle.Mapping.txt" />
    <Content Include="libfko.arm.dll" />
    <Content Include="libfko.x86.dll" />
    <Content Include="libfko.x64.dll" />
    <Content Include="menu_1.png" />
    <Content Include="Properties\Default.rd.xml" />
    <Content Include="Assets\LockScreenLogo.scale-100.png" />
    <Content Include="Assets\LockScreenLogo.scale-125.png" />
    <Content Include="Assets\LockScreenLogo.scale-150.png" />
    <Content Include="Assets\LockScreenLogo.scale-200.png" />
    <Content Include="Assets\LockScreenLogo.scale-400.png" />
    <Content Include="Assets\SplashScreen.scale-100.png" />
    <Content Include="Assets\SplashScreen.scale-125.png" />
    <Content Include="Assets\SplashScreen.scale-150.png" />
    <Content Include="Assets\SplashScreen.scale-200.png" />
    <Content Include="Assets\SplashScreen.scale-400.png" />
    <Content Include="Assets\Square150x150Logo.scale-200.png" />
    <Content Include="Assets\Square44x44Logo.scale-100.png" />
    <Content Include="Assets\Square44x44Logo.scale-125.png" />
    <Content Include="Assets\Square44x44Logo.scale-150.png" />
    <Content Include="Assets\Square44x44Logo.scale-200.png" />
    <Content Include="Assets\Square44x44Logo.scale-400.png" />
    <Content Include="Assets\Square44x44Logo.targetsize-16_altform-unplated.png" />
    <Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
    <Content Include="Assets\Square44x44Logo.targetsize-32_altform-unplated.png" />
    <Content Include="Assets\Square44x44Logo.targetsize-48_altform-unplated.png" />
    <Content Include="Assets\Square44x44Logo.targetsize-256_altform-unplated.png" />
    <Content Include="Assets\StoreLogo.png" />
    <Content Include="Assets\Wide310x150Logo.scale-100.png" />
    <Content Include="Assets\Wide310x150Logo.scale-125.png" />
    <Content Include="Assets\Wide310x150Logo.scale-150.png" />
    <Content Include="Assets\Wide310x150Logo.scale-200.png" />
    <Content Include="Assets\Wide310x150Logo.scale-400.png" />
    <Content Include="WindowsFullTrustProcess.exe">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
    <Content Include="refresh.png" />
  </ItemGroup>
  <ItemGroup>
    <ApplicationDefinition Include="App.xaml">
      <Generator>MSBuild:Compile</Generator>
      <SubType>Designer</SubType>
    </ApplicationDefinition>
    <Page Include="MainPage.xaml">
      <Generator>MSBuild:Compile</Generator>
      <SubType>Designer</SubType>
    </Page>
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="AWSSDK.CognitoIdentity">
      <Version>3.3.2.17</Version>
    </PackageReference>
    <PackageReference Include="AWSSDK.CognitoIdentityProvider">
      <Version>3.3.8</Version>
    </PackageReference>
    <PackageReference Include="AWSSDK.Extensions.CognitoAuthentication">
      <Version>0.9.1</Version>
    </PackageReference>
    <PackageReference Include="BouncyCastle">
      <Version>1.8.1</Version>
    </PackageReference>
    <PackageReference Include="Fwknop">
      <Version>1.0.1</Version>
    </PackageReference>
    <PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
      <Version>6.0.6</Version>
    </PackageReference>
    <PackageReference Include="Microsoft.Toolkit.Uwp.Notifications">
      <Version>2.1.1</Version>
    </PackageReference>
    <PackageReference Include="NETStandard.Library">
      <Version>2.0.1</Version>
    </PackageReference>
    <PackageReference Include="Newtonsoft.Json">
      <Version>11.0.1-beta3</Version>
    </PackageReference>
    <PackageReference Include="QueryString.NET">
      <Version>1.0.0</Version>
    </PackageReference>
    <PackageReference Include="Serilog">
      <Version>2.6.1-dev-00938</Version>
    </PackageReference>
    <PackageReference Include="Serilog.Sinks.Console">
      <Version>3.1.1</Version>
    </PackageReference>
    <PackageReference Include="Serilog.Sinks.Debug">
      <Version>1.0.1-dev-00015</Version>
    </PackageReference>
    <PackageReference Include="Serilog.Sinks.File">
      <Version>4.0.1-dev-00790</Version>
    </PackageReference>
    <PackageReference Include="System.Net.Http">
      <Version>4.3.3</Version>
    </PackageReference>
    <PackageReference Include="System.Security.Cryptography.OpenSsl">
      <Version>4.4.0</Version>
    </PackageReference>
    <PackageReference Include="System.Threading">
      <Version>4.3.0</Version>
    </PackageReference>
    <PackageReference Include="System.Threading.Tasks">
      <Version>4.3.0</Version>
    </PackageReference>
    <PackageReference Include="System.Threading.Timer">
      <Version>4.3.0</Version>
    </PackageReference>
    <PackageReference Include="Xamarin.Forms">
      <Version>2.5.0.122203</Version>
    </PackageReference>
  </ItemGroup>
  <ItemGroup>
    <SDKReference Include="WindowsDesktop, Version=10.0.16299.0">
      <Name>Windows Desktop Extensions for the UWP</Name>
    </SDKReference>
  </ItemGroup>
  <ItemGroup>
    <WCFMetadata Include="Connected Services\" />
  </ItemGroup>
  <PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
    <VisualStudioVersion>14.0</VisualStudioVersion>
  </PropertyGroup>
  <Import Project="..\SDPNativeClient\SDPNativeClient.projitems" Label="Shared" Condition="Exists('..\SDPNativeClient\SDPNativeClient.projitems')" />
  <Import Project="..\..\WindowsAppServiceIPC\WindowsAppServiceIPC.projitems" Label="Shared" />
  <Import Project="..\..\WindowsFullTrustProcessShared\WindowsFullTrustProcessShared.projitems" Label="Shared" />
  <Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
  <PropertyGroup>
    <PreBuildEvent>"$(msbuildbinpath)\msbuild.exe" $(SolutionPath) /t:WindowsFullTrustProcess:Rebuild</PreBuildEvent>
  </PropertyGroup>
  <PropertyGroup>
    <PostBuildEvent>
    </PostBuildEvent>
  </PropertyGroup>
  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
       Other similar extension points exist, see Microsoft.Common.targets.
  <Target Name="BeforeBuild">
  </Target>
  <Target Name="AfterBuild">
  </Target>
  -->
</Project>

Local time used where UTC should be

Local time is used to keep track of timestamps when UTC should be used, otherwise time updates such as daylight savings shifts will cause errors.

        private CognitoUserSession GetCognitoUserSession(AuthenticationResultType authResult, string refreshTokenOverride = null)
        {
            string idToken = authResult.IdToken;
            string accessToken = authResult.AccessToken;
            string refreshToken;
            DateTime currentTime = DateTime.Now;

awssdk.extensions.cognitoauthentication\cognitouser.cs

        /// <summary>
        /// Determines if the tokens for a user are still valid
        /// </summary>
        /// <returns>Returns a boolean whether the user's tokens are still valid</returns>
        public bool IsValid()
        {
            DateTime currentTimeStamp = DateTime.Now;

awssdk.extensions.cognitoauthentication\cognitouser.cs

Method not found AmazonCognitoIdentityProviderClient

I'm getting an error of System.MissingMethodException at this line:

var provider = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials(), FallbackRegionFactory.GetRegionEndpoint());

The full error is:
Method not found: void Amazon.CognitoIdentityProvider.AmazonCognitoIdentityProviderClient..ctor(Amazon.RegionEndpoint)

I'm on Visual Studio 2019 for Mac.

It does look like a couple other people may be having the same issue.

Since I don't get the dependencies added automatically by the Windows SDK tools and templates I think it may just be that I'm missing something there. I've added AWSSDK.Core. I tried also adding AWSSDK.CognitoIdentity and AWSSDK.CognitoIdentityProvider even though they are already included as dependencies. No luck though.

Obviously the constructor does exist at design time - I can drill down on it in the IDE and see it inside the nuget package. But when I run the code my app will crash if I include any method that has a new AmazonCognitoIdentityProviderClient() inside it.

There doesn't appear to be an ability to use UserContextData

Describe the feature

I would like to be able to pass the UserContextData related to the user to the auth flow request as documented in the InitiateAuth API documentation.

Use Case

I want to be able to use the Advanced Security Features of Cognito with the SRP flow

Proposed Solution

No response

Other Information

No response

Acknowledgements

  • I may be able to implement this feature request
  • This feature might incur a breaking change

AWS .NET SDK and/or Package version used

AWSSDK.CognitoIdentity 3.3.0.0
AWSSDK.CognitoIdentityProvider 3.3.0.0
AWSSDK.Core 3.3.0.0
AWSSDK.SecurityToken 3.3.0.0

Targeted .NET Platform

.NET 6

Operating System and version

macOS, Linux

Cognito StartWithRefreshTokenAuthAsync Deletes RefreshToken

Given following code example:

            usr = new CognitoUser(username, AWS_CLIENT_ID, AwsUserPool, AwsIdpClient)
            {
                SessionTokens = new CognitoUserSession(
                                               null, null, refreshToken, 
                                              DateTime.Now, DateTime.Now.AddDays(3))
            };

                AuthFlowResponse context = await usr.StartWithRefreshTokenAuthAsync(
                    new InitiateRefreshTokenAuthRequest() { AuthFlowType = AuthFlowType.REFRESH_TOKEN }
                    ).ConfigureAwait(false);

Expected Outcome:
usr.SessionTokens is fully populated, including the (still valid) Refresh Token.

Actual Outcome:
usr.SesisonTokens is populated with new accessToken, ExpirationTime, IdToken and IssuedTime, but the RefreshToken is null. It needs to keep the Refresh Token supplied as the AuthenticationResult does not return any RefreshToken.

Recent change to use DateTime.UtcNow was a breaking change (at least for our application)

Description

I just wanted to highlight this recent change to switch all usage of DateTime.Now to be DateTime.UtcNow was a breaking change for our application and potentially also other applications that may use apis like DateTime.Subtract() on any of the DateTime values exposed by this api.

In our case the issue was that we had some code like this for checking how many seconds were left before a token would expire:

var accessTimeLeft = user.SessionTokens.ExpirationTime.Subtract(DateTime.Now).TotalSeconds;

but the problem here is that it assumes that the ExpirationTime uses the same timezone as DateTime.Now (otherwise DateTime.Subtract() doesn't really have meaningful / expected results.

Resolution

I mean to be fair our code probably shouldn't have been making any assumption about the timezone used and can easily be updated so that we aren't dependent on the timezone used internally but still since this was changed recently maybe it would be good to add some clear documentation about the change somewhere as a potential warning in case anyone else has unwittingly made their app dependent on the old behaviour.


This is a 🐛 bug-report

Enable Advanced Security in Xamarin

Hi,

According to this you can enable Advanced Security for JS, iOS and Android but there is no mention for Xamarin.

Is there any way to enable the same?

Thanks !

NotAuthorizedException: SecretHash does not match for the client: xxxxxxxxxxxxxxxxxxx when trying refresh token flow

Describe the bug

Hi,
I had an issue when trying to use RefreshToken flow. I get error:
NotAuthorizedException: SecretHash does not match for the client: xxxxxxxxxxxxxxxxxxx
I tried:
-using secret directly
-using GetSecretHash with userName, userEmail, USerID, User Sub Id
Always the same issue.

I'm trying:

 public async void GetCredsFromRefreshAsync_(string refreshToken, string accessToken, string idToken, string userName, string userId)
{
  var secretHash = GetSecretHash(userId + _cognitoCredentials.AppClientId);
            CognitoUserPool userPool = new CognitoUserPool(_cognitoCredentials.UserPoolId, _cognitoCredentials.AppClientId, _provider, _cognitoCredentials.Secret);
            CognitoUser user = new CognitoUser(userName, _cognitoCredentials.AppClientId, userPool, _provider, _cognitoCredentials.Secret);
            user.SessionTokens = new CognitoUserSession( null, null, refreshToken, DateTime.Now, DateTime.Now.AddHours(1));
            InitiateRefreshTokenAuthRequest refreshRequest = new InitiateRefreshTokenAuthRequest()
            {               
                AuthFlowType = AuthFlowType.REFRESH_TOKEN_AUTH
            };

            AuthFlowResponse authResponse = await user.StartWithRefreshTokenAuthAsync(refreshRequest).ConfigureAwait(false);`
}

        private string GetSecretHash(string value)
        {
            var key = _cognitoCredentials.Secret;
            using (var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(key)))
            {
                var hash = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(value));
                return Convert.ToBase64String(hash);
            }
        }

Also tried with the same result:

       public async void GetCredsFromRefreshAsync(string refreshToken, string accessToken, string idToken, string userName, string userId)
        {
            var secretHash = GetSecretHash(userId + _cognitoCredentials.AppClientId);
            CognitoUserPool userPool = new CognitoUserPool(_cognitoCredentials.UserPoolId, _cognitoCredentials.AppClientId, _provider);
            CognitoUser user = new CognitoUser(userName, _cognitoCredentials.AppClientId, userPool, _provider);

            user.SessionTokens = new CognitoUserSession(idToken, accessToken, refreshToken, DateTime.Now, DateTime.Now.AddHours(1));

            var refreshReq = new InitiateAuthRequest();
            refreshReq.ClientId = _cognitoCredentials.AppClientId;

            refreshReq.AuthFlow = AuthFlowType.REFRESH_TOKEN_AUTH;
            refreshReq.AuthParameters.Add("SECRET_HASH", secretHash);
            refreshReq.AuthParameters.Add("REFRESH_TOKEN", refreshToken);


            var clientResp = await _provider.InitiateAuthAsync(refreshReq).ConfigureAwait(false);

            InitiateRefreshTokenAuthRequest refreshRequest = new InitiateRefreshTokenAuthRequest()
            {
                AuthFlowType = AuthFlowType.REFRESH_TOKEN_AUTH
            };
        }

Please help.

Expected Behavior

Get Refresh Token without error: NotAuthorizedException: SecretHash does not match for the client

Current Behavior

Cannot get Refresh Token, error occurs: NotAuthorizedException: SecretHash does not match for the client

Reproduction Steps

Use this code:

public async void GetCredsFromRefreshAsync_(string refreshToken, string accessToken, string idToken, string userName, string userId)
{
  var secretHash = GetSecretHash(userId + _cognitoCredentials.AppClientId);
            CognitoUserPool userPool = new CognitoUserPool(_cognitoCredentials.UserPoolId, _cognitoCredentials.AppClientId, _provider, _cognitoCredentials.Secret);
            CognitoUser user = new CognitoUser(userName, _cognitoCredentials.AppClientId, userPool, _provider, _cognitoCredentials.Secret);
            user.SessionTokens = new CognitoUserSession( null, null, refreshToken, DateTime.Now, DateTime.Now.AddHours(1));
            InitiateRefreshTokenAuthRequest refreshRequest = new InitiateRefreshTokenAuthRequest()
            {               
                AuthFlowType = AuthFlowType.REFRESH_TOKEN_AUTH
            };

            AuthFlowResponse authResponse = await user.StartWithRefreshTokenAuthAsync(refreshRequest).ConfigureAwait(false);`
}

        private string GetSecretHash(string value)
        {
            var key = _cognitoCredentials.Secret;
            using (var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(key)))
            {
                var hash = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(value));
                return Convert.ToBase64String(hash);
            }
        }

Possible Solution

Please give me information, what is wrong with my code, or maybe there is some bug?

Additional Information/Context

No response

AWS .NET SDK and/or Package version used

Amazon.Extensions.CognitoAuthentication 2.2.1
Unity 2021.3.9f1

Targeted .NET Platform

.Net 4.x

Operating System and version

Windows 11

UserNotConfirmedException - how to resend confirmation code for not completed signup in .NET

Describe the bug

This is just a question:
After signup, the user gets Confirmation Code.
However, if the user doesn't enter the confirmation code, next time when trying signUp, he gets an exception: UserNotConfirmedException.
So question is, how to resend the confirmation code for not completed signup in .NET?

Expected Behavior

Can re-send confirmation code for signup flow

Current Behavior

Cannot re-send confirmation code for signup flow

Reproduction Steps

Use SingUp flow like here:

Possible Solution

No response

Additional Information/Context

No response

AWS .NET SDK and/or Package version used

AWS for Unity .NET

Targeted .NET Platform

Unity .NET

Operating System and version

Windows 11

Async methods should ALWAYS accept an optional cancellation token

Describe the feature

Feature: All async methods should accept an optional cancellation token.

Examples of methods that do not satisfy these requirements:

  • StartWithSrpAuthAsync
  • StartWithRefreshTokenAuthAsync

Pertains to package version 2.4.0 (latest version on NuGet as of this time)

Use Case

Observation: authorization requests NEVER timeout - even if there is no network connection. I have tried waiting for an hour, and the authorization will just wait until enable a network connection.

Use-case: If an application is running with NO network connection, a thread that awaits an authorization request will never restart. However, if the authorization is a background task it cannot be cancelled, so an IDisposable pattern can't work and a resource leak is likely. Furthermore, the standard SDK methods all accept cancellation tokens, so this pattern change is really odd.

Work-around: Use the SDK source code and make the necessary changes.

Proposed Solution

Have an optional CancellationToken argument in the StartWithSrpAuthAsync method. Pass this to the invoked SDK methods (which already have optional cancellation tokens).

That's all it would take... just stick with the existing design pattern. Since the arguments are optional no code that currently uses these methods would need to change.

Other Information

No response

Acknowledgements

  • I may be able to implement this feature request
  • This feature might incur a breaking change

AWS .NET SDK and/or Package version used

AWS SDK Extensions for .NET Standard 2.0 (compatible with .NET Framework 4.5)
Version 2.4.0
https://www.nuget.org/packages/Amazon.Extensions.CognitoAuthentication/

Targeted .NET Platform

.NET Framework 4.5

Operating System and version

Ubuntu 22.04

Unable to re-authenticate (not refresh) using the same device key

Describe the bug

I am attempting to use the aws-sdk-net-extensions-cognito library for Cognito authentication with device tracking enabled. The cloud formation properties on the User Pool for this configuration are:

DeviceConfiguration:
    ChallengeRequiredOnNewDevice: false
    DeviceOnlyRememberedOnUserPrompt: false

I can successfully complete the following steps:

  • User logins in the for the first time using StartWithSrpAuthAsync (generate a new device key)
  • Use the NewDeviceMetadata to create a DeviceVerifier which includes PasswordVerifier and Salt
  • Use this to ConfirmDeviceAsync which shows the new device for the user in the Cognito AWS Console dashboard
  • As long as the device key is set on the user I can invoke StartWithRefreshTokenAuthAsync to successfully get refresh tokens

My issue at this point is that signing out and attempting to sign back in fails using the device key from the previous session. I know I need to generate a new token but I shouldn't have to regenerate the device key on the same device. Currently, when I tried to login using the device key from the previous session I get the following error:

"Incorrect username or password."

Here is my code for attempting to login using a local device key from the previous session:

user.Device = new CognitoDevice(
    new DeviceType { DeviceKey = deviceKey },
    user
);

var deviceVerifier = user.GenerateDeviceVerifier(DeviceInfo.DeviceGroupKey, password, DeviceInfo.DeviceKey);

authRequest = new InitiateSrpAuthRequest()
{
    Password = password,
    DeviceGroupKey = deviceGroupKey,
    DevicePass = deviceVerifier.PasswordVerifier,
    DeviceVerifier = deviceVerifier.Salt
};

// Fails with 400 error mentioned above
var authResponse = await user.StartWithSrpAuthAsync(authRequest);

I have a feeling it's related to the creation of new InitiateSrpAuthRequest() and the values I am providing. I was unable to find documentation around these parameter values. I was assuming DevicePass is the PasswordVerifier created by GenerateDeviceVerifier and DeviceVerifier is the Salt from GenerateDeviceVerifier but the key names are confusing?

TLDR: What values are expected for DevicePass and DeviceVerifier or am I doing something else incorrectly?

Expected Behavior

I can re-authenticate a user (not refresh) but use the same device key which will not create a new device for that user as long as they are on the same machine.

Current Behavior

  • Initial token/device key creation works
  • Token refresh works when device key is provided
  • Logging out and logging back in fails due "Incorrect username or password."
    • The only difference with the initial auth is the parameters we pass to InitiateSrpAuthRequest()
    • The initial login we only provide the Password
    • Reoccurring logins where a local device key is found in the cache we provide Password, DeviceGroupKey, DevicePass and DeviceVerifier which fails

AWS .NET SDK and/or Package version used

Amazon.Extensions.CognitoAuthentication 2.5.2 (latest)

Targeted .NET Platform

.NET Framework 4.8 & .NET 6.0

Operating System and version

Windows 10/11

Unable to create new access token from only refresh token.

The Readme shows a refresh token scenario that requires that the users username be known in advance so that the users CognitoUser object can be retrieved and its methods thus called.

The code itself in the readme is not functional; the constants "username" etc are clearly placeholders meant to show that a developer should use the correct username for that specific CognitoUser in question, the same as I would presume the other fields are meant to be used for pool id and client id configuration parameters,, but that's not even represented in the signature of the method itself, so at best its a non-working example that's actively misleading, if not outright hostile to users, because it gives them false hope of a working solution.

And in case I was wrong on this, I actually tried to use the code after setting up config values.. and found that attempting to actually use it just results in an error in my tests, in my case a "NotAuthorizedException" in my tests, no doubt because that user doesn't exist in my test user pool as I'm otherwise able to generate a access token log in a user, etc. It does not work, so I'm confused as to why the readme actively misdirects people.

I'm also noticing that it uses DateTime.Now instead of DateTime.UtcNow in a few places, so there is another issue.

Another issue: When an API client hits a 401 and the server challenges the bearer, it now is told that the AccessToken has expired, but the redirect doesn't pass in any other data at all.

Simply put: How do we actually get a new auth token from only a refresh token that according to the spec is everything we should need, if that is all we have, in the call? How can we securely create a new access tokens for a user without knowing the username of the user in advance, using only the refresh token itself as input?

I'm asking for a working solution. Not hypotheticals. Thanks.

warning NU1608: Detected package version outside of dependency constraint: Amazon.Extensions.CognitoAuthentication 1.0.3 requires AWSSDK.CognitoIdentity (>= 3.3.100 && < 3.4.0) but version AWSSDK.CognitoIdentity 3.5.0.4 was resolved

There has been an update to AWSSDK.Core from 3.4 to 3.5. I'm using a lot of AWSSDK libraries and some are bringing 3.5 in. The dependencies for this project are somewhere locked to AWSSDK.Core 3.4. This is bringing a lot of grief. Can the dependencies be updated to allow for 3.5?

warning NU1608: Detected package version outside of dependency constraint: Amazon.Extensions.CognitoAuthentication 1.0.3 requires AWSSDK.CognitoIdentity (>= 3.3.100 && < 3.4.0) but version AWSSDK.CognitoIdentity 3.5.0.4 was resolved

TOTP support

I am attempting to set up a user pool with Multi-Factor Authentication and allow users to select a Time-based One-time Password using Google Authenticator. How do you respond to a challenge of type SOFTWARE_TOKEN_MFA using AWS .Net SDK?

ASP.Net Core 3 with Identity
Amazon.Extensions.CognitoAuthentication Version=1.0.4

refresh token with MFA optional on user not opted in to MFA

I have a user pool with MFA set as optional. Remembering devices is set to always and that is used to suppress MFA on remembered devices. I am using it via the API through the .Net SDK without the extension library yet: will the following be possible to solve using the extension library?

The first issue is how to get deviceKey for users who do not have MFA enabled? With MFA enabled, and when finally getting the tokens (after MFA), the response includes new device metadata with the device key.

However, if I have a user without MFA enabled, and use the USER_PASSWORD flow, I get the tokens back without a device key. NewDeviceMetadata is null.

Using this refresh token results in error "invalid refresh token" (likely because there is no device key).

So my question is that if I start from the .Net client with USER_PASSWORD flow, how do I get the device key for users who do not opt in to MFA?

The second issue is: With .Net SDK, how can I compute the device secret, salt, and password verifier needed to call ConfirmDevice, because it seems without that, the device will not be remembered and I cannot use the refresh token.

(As an aside, I was able to use the refresh token successfully if turn off device tracking, but then MFA cannot be suppressed on previously used devices.)

Custom Authentication Flow with SRP Password Verification

The Question

I'm looking for a best way to implement a Custom Authentication Flow which consists of two steps:

  1. SRP Password Verification
  2. Custom challenge (SMS code verification)
public async Task AuthenticateWithCustomAuthAndSrpAsync(string poolId, string clientId, string userName, string password)
        {
            var provider = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials(), FallbackRegionFactory.GetRegionEndpoint());
            var userPool = new CognitoUserPool(poolId, clientId, provider);
            var user = new CognitoUser(userName, clientId, userPool, provider);

            AuthFlowResponse authResponse = await user.StartWithCustomAuthAsync(new InitiateCustomAuthRequest
            {
                AuthParameters = new Dictionary<string, string>()
                {
                    {"USERNAME", userName},
                    {"SECRET_HASH", ComputeHash(userName)},
                    {"CHALLENGE_NAME", "CUSTOM_CHALLENGE"}
                },
                ClientMetadata = new Dictionary<string, string>()
            }).ConfigureAwait(false);

            var adminRespondToAuthChallengeAsync = await provider.AdminRespondToAuthChallengeAsync(
                new AdminRespondToAuthChallengeRequest
                {
                    ClientId = clientId,
                    UserPoolId = poolId,
                    ChallengeName = "PASSWORD_VERIFIER",
                    Session = authResponse.SessionID,
                    ChallengeResponses = new Dictionary<string, string>
                    {
                        {"USERNAME", userName},
                        {"CHALLENGE_NAME", "PASSWORD_VERIFIER"},
                        {"PASSWORD_CLAIM_SIGNATURE", ""}, // <== Is there a way to calculate it?
                        {"PASSWORD_CLAIM_SECRET_BLOCK", ""}, // <== Is there a way to calculate it?
                        {"TIMESTAMP", ""} // <== Is there a way to calculate it?
                    }
                });
        }

The problem is that SRP Password Verification requires next parameters: PASSWORD_CLAIM_SIGNATURE, PASSWORD_CLAIM_SECRET_BLOCK and TIMESTAMP, but seems like library calculates these properties internally and there is no way to get them from the caller code. Am I missing something?

Verification codes other than the first one are not working

Describe the bug

I'm not actually sure whether this is SDK or Cognito problem or maybe I just missed something, but any help would be much appreciated.

I have a user pool set up in AWS Cognito. I've created a user and made it confirmed be changing the password via RespondToNewPasswordRequiredAsync.

I'm trying to implement 'Forgot Password' feature in my system. After making a 'ForgotPasswordAsync' I successfully receive a verification code.

However, I also try to implement a 'Resend verification code' feature. And whilst I do receive a new code, I get an 'Invalid verification code' exception. And this happens for every code other than the first one.

image

I thought that maybe there is some time that enables new codes, but I've tried to wait 1, 5 and 10 minutes and no success was accomplished.

As I said, the first one received is working with no issues whatsoever.

image

Expected Behavior

Any received code should work or at least the latest one.

Current Behavior

Only the first code received works

Reproduction Steps

  1. Create a user pool in AWS Cognito.
  2. Create a new user with verified email.
  3. Change this user's password so it becomes 'Confirmed'.
  4. Make a 'Forgot Password' request with SDK.
  5. Receive a code but ignore it
  6. Make a 'Resend confirmation code' request with SDK.
  7. Make a 'Confirm Forgot Password' request with the latest code received

Possible Solution

No solutions were found

Additional Information/Context

No response

AWS .NET SDK and/or Package version used

Amazon.Extensions.CognitoAuthentication: 2.5.2
AWSSDK.CognitoIdentity: 3.7.300.10
AWSSDK.CognitoIdentityProvider: 3.7.300.10
AWSSDK.Core: 3.7.300.10

Targeted .NET Platform

.NET 6

Operating System and version

Windows 10, AmazonLinux (docker container)

Refresh Token error - SecretHash does not match for the client

Describe the bug

When calling StartWithRefreshTokenAuthAsync, I am receiving an error Amazon.CognitoIdentityProvider.Model.NotAuthorizedException: 'SecretHash does not match for the client: xxxxxxxxxxxx.

I have double-checked the calculation of the SecretHash and it looks correct for me. When I use the SRP AuthFlow it works just fine using the exact same SecretHash value. I captured the web traffic for the POST request sent to the api and the request syntax matches the InitiateAuth documentation.

I can see that others have reported this problem in this repo here and here. I looked through it and used this code to try and reproduce the bug. I get the same error regarding the SecretHash.

Expected Behavior

I am expecting a response from the API.

Current Behavior

I am receiving an error Amazon.CognitoIdentityProvider.Model.NotAuthorizedException: 'SecretHash does not match for the client: xxxxxxxxxxxx.

Reproduction Steps

I looked through it and used this code to try and reproduce the bug. I get the same error regarding the SecretHash.

Possible Solution

No response

Additional Information/Context

I also have seen a comment on stack overflow that instead of user email being used in the secret hash you actually need to use the sub value. In this case the SecretHash value differs from the SRP auth flow but the result is the same: 'SecretHash does not match for the client:`.

AWS .NET SDK and/or Package version used

Amazon.Extensions.CognitoAuthentication v2.4.2

Targeted .NET Platform

.net6

Operating System and version

Windows 10

StartWithSrpAuthAsync Not Sync Safe

Describe the bug

When authenticating with Cognito credentials according to the basic authentication example on the AWS SDK for .NET documentation using the StartWithSrpAuthAsync function, the overload which does not take a cancellation token lacks a .ConfigureAwait(false) and thus causes a deadlock scenario when used from a Synchronous context.

https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/cognito-authentication-extension.html

This was discovered while making a service call from a 3rd party CMS which is not asynchronous and requires us to do .Result on the response and block waiting for the call.

Line in question:
https://github.com/aws/aws-sdk-net-extensions-cognito/blob/master/src/Amazon.Extensions.CognitoAuthentication/CognitoUserAuthentication.cs#L45

Please let me know if the proposed solution is acceptable and you would like a PR submitted for it.

Thank you kindly!

Expected Behavior

The SDK is usable from both asynchronous and synchronous contexts and returns a successful JWT token.

Current Behavior

The asynchronous thread marshaling back to the calling thread deadlocks the application.

Reproduction Steps

static Main(string[] args) {
  string token = GetCognitoTokenAsync().Result;
  Console.WriteLine(token);
}

private async Task<string> GetCognitoTokenAsync() {
  var provider = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials(), Amazon.RegionEndpoint.USEast2);
  var userPool = new CognitoUserPool(userPoolId, clientId, provider);
  var user = new CognitoUser(serviceUsername, clientId, userPool, provider, serviceClientSecret);

  var authRequest = new InitiateSrpAuthRequest() { Password = userPassword };
  AuthFlowResponse authResponse = await user.StartWithSrpAuthAsync(authRequest).ConfigureAwait(false);

  return authResponse.AuthenticationResult.IdToken;
}

Possible Solution

The async and await on the overload without the cancellation token are unnecessary and can be removed. This would result in using the other overloads proper handling of async contexts without adding additional code.

public virtual Task<AuthFlowResponse> StartWithSrpAuthAsync(InitiateSrpAuthRequest srpRequest)
{
  return StartWithSrpAuthAsync(srpRequest, default);
}

Additional Information/Context

The method overload which does accept a CancellationToken has complete usage of .ConfigureAwait(false) and we were able to make use of this as a workaround for now.

AWS .NET SDK and/or Package version used

Amazon.Extensions.CognitoAuthentication.2.4.2

Targeted .NET Platform

.Net Framework 4.8.2

Operating System and version

Windows 11

StartWithSrpAuthAsync fails with a parse exception

I have a cognito user pool built using the email as a sign-in alias. When I use [email protected] as a username using StartWithSrpAuthAsync, the library throws an exception "The value could not be parsed."

I narrowed this down to the fact the salt string is a negative hex value, which the lib is assuming is always unsigned. This error is occuring in AuthenticationHelper.cs:

var salt = BigIntegerExtensions.FromLittleEndianHex(saltString);

Is it possible to support signed salt values here? I tried this in nodejs Amplify and they seem to handle it w/o an issue.

Failed To Write Unit Tests: CognitoUserPool Constructor Receives AmazonCognitoIdentityProviderClient Instance

Hi,
I'm writing a unit test, and in my code I'd like to use dependency injection for my Cognito Identity Provider, so I can mock it in my unit tests. But the CognitoUserPool received the AmazonCognitoIdentityProviderClient as a constructor argument.
Also, I want my Identity Provider registered as a singleton, because my application will use only one Identity Provider for all my users pool.
Is there a workaround or recommendation how to make this happen?
Adding a code sample below.
Thanks

internal class LoginHandler
{ 
  private readonly IAmazonCognitoIdentityProvider _identityProvider;
  public LoginHandler(IAmazonCognitoIdentityProvider identityProvider)
  {
     _identityProvider = identityProvider;
  }

  public override async Task<AuthResponse> LoginAsync(string clientId, string clientSecret, string username)
  {
    var userPool = new CognitoUserPool("app-user-pool-id", clientId, _identityProvider, clientSecret);
    throw new NotImplementedException();
  }
}

Aws coginto refresh token problem

Dear @ashishdhingra ,
I am using latest version of Amazon.Extensions.CognitoAuthentication" version="2.0.3" targetFramework="net472"
I still I am facing same problem cognito token expire after one hour (also after refresh). I am using

  1. Get coginto user information by using user name and password

  2. Refresh cognito token

  3. Get cognito user credentials by using this method var credentials=user.GetCognitoAWSCredentials(FED_POOL_ID, new AppConfigAWSRegion().Region);

  4. Get AccessKey, SecretKey,Token from "credentials" variable in step 3, by using
    var AccessKey= credentials.GetCredentials().AccessKey,
    var SecretKey= credentials.GetCredentials().SecretKey,
    var Token= credentials.GetCredentials().Token.

  5. use these credentials information and intialize
    Client = new AmazonIotDataClient(string awsAccessKeyId, string awsSecretAccessKey, string awsSessionToken, string serviceUrl);

By using these step my credentials expire after one hour.

if I use Client =new AmazonIotDataClient(string serviceUrl, AWSCredentials credentials);

then it's working fine. but in my case i want to use accesskey, secretKey, and token for third party API

Here I also want to share a another problem. Although I have set access token expiration time 1000 min or 5mint but my token will expire after one hour.
I am sending some screen shots
Please check it where I doing mistake.

4
1
2
3

Invalid Refresh Token when using Refresh Token with Device Tracking

I followed the examples for Authentication and I was able to get it to retrieve an access token and refresh token. When trying to use toe refresh token to reauthenticate, it is failing if I have device tracking turned on. I came across #75 and it looks like someone else had the same issue but never replied with their result from testing. Seems to still be broken if Device Tracking is turned on and returns Amazon.CognitoIdentityProvider.Model.NotAuthorizedException: Invalid Refresh Token.

Avoid checking _access_ token expiry when trying to refresh access via a refresh token.

Description

Right now there is an awkward chicken and egg situation when trying to refresh expired access tokens...

As a workaround we've been doing the following to create fake user SessionToken state that we know will pass the internal EnsureAuthenticated() check that's done before making any InitiateAuthAsync() request...

// Create a fake expiry time for our current session tokens otherwise the internal call to
// EnsureUserAuthenticated() will see that our access token is expired and won't let us refresh it!
user.SessionTokens = new CognitoUserSession(null, null, refreshToken, DateTime.Now, DateTime.Now.AddHours(1));
var refreshReq = new InitiateRefreshTokenAuthRequest() {
        AuthFlowType = AuthFlowType.REFRESH_TOKEN_AUTH
};

If we don't do this then we get an authentication failure while trying to refresh expired access tokens.

Environment

  • Build Version: 2.2.1
  • Targeted .NET Platform: netstandard 2.0

Resolution

I think perhaps it would make sense to just drop the call to EnsureAuthenticated() from the top of CreateRefreshTokenAuthRequest:

private InitiateAuthRequest CreateRefreshTokenAuthRequest(AuthFlowType authFlowType)

Alternatively maybe there could be a check on the expiry of the refresh token instead of the access token in this context.


This is a 🐛 bug-report

Missing Authentication Token when trying to use ListUsersRequest

Describe the bug

I got the error, when trying to use ListUsersRequest (in forgotten password flow )

Missing Authentication Token Amazon.Runtime.Internal.HttpErrorResponseException: Exception of type 'Amazon.Runtime.Internal.HttpErrorResponseException' was thrown.

 private async Task<ListUsersResponse> FindUsersByEmailAddress(string mail)
        {
            ListUsersRequest listUsersRequest = new ListUsersRequest
            {
                UserPoolId = _cognitoCredentials.UserPoolId, 
                Filter = $"email=\"{mail}\""
            };
            return await _provider.ListUsersAsync(listUsersRequest);
        }

Expected Behavior

No error, get a list of registered users from Cognito.

Current Behavior

Error is thrown:
Missing Authentication Token Amazon.Runtime.Internal.HttpErrorResponseException: Exception of type 'Amazon.Runtime.Internal.HttpErrorResponseException' was thrown.

Reproduction Steps

Use this method to get list of available users:

private async Task<ListUsersResponse> FindUsersByEmailAddress(string mail)
        {
            ListUsersRequest listUsersRequest = new ListUsersRequest
            {
                UserPoolId = _cognitoCredentials.UserPoolId, 
                Filter = $"email=\"{mail}\""
            };
            return await _provider.ListUsersAsync(listUsersRequest);
        }

Possible Solution

No response

Additional Information/Context

No response

AWS .NET SDK and/or Package version used

Unity 2021.3.9
Aws sdk .net

Targeted .NET Platform

.Net 4.x

Operating System and version

Windows 11

Awaiting UpdateAttributesAsync() throws a NullReferenceException

As the title implies, awaiting the UpdateAttributesAsync method causes a NRE to be thrown.

I am able to successfully update attributes when the method is not awaited, but this has the drawbacks of not knowing whether the the update was successful, and the inability to catch any real errors during the update process.

For testing, I am using this method after successful login, passing in the authenticated CognitoUser:

public async Task UpdateAttributes(CognitoUser user)
        {
            try
            {
                Dictionary<string, string> userAttributes = new Dictionary<string, string>();
                userAttributes.Add("custom:custom_attribute_name", "0");

                await user.UpdateAttributesAsync(userAttributes);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

A deadlock occurs with Android and C# when trying to create a provider with Amazon.CognitoIdentityProvider.AmazonCognitoIdentityProviderClient

Description

Hi.

I'm using the AWS Samples C# project named aws-cognito-dot-net-desktop-app as a reference:

https://github.com/aws-samples/aws-cognito-dot-net-desktop-app

The code of this project I am using it with C # and WPF and it works correctly (app for desktop PC).

Now, I'm doing the exact same thing but with Android and C# in Visual Studio.

When you want to register a user, the task called SignUpUser is executed, but when trying to create a provider with Amazon.CognitoIdentityProvider.AmazonCognitoIdentityProviderClient the code remains frozen in that line (deadlock)

This is an image of where the problem happens:

image

No exception or error message occurs.

It happens both in a real mobile phone and in a virtual phone.

It is as if some permission or something else needs to be enabled, even though internet and wifi permissions are enabled in the manifest.

Reproduction Steps

  1. Create a project of type Xamarin (Not Xamarin Forms) with Visual Studio 2019

  2. Copy or create the CognitoHelper class in the project, it is the same as aws-cognito-dot-net-desktop-app.

  3. Do not forget to install all the packages that correspond to Amazon ()using Amazon.CognitoIdentity, using Amazon.S3.Model, etc)

  4. From another class you can invoke the task of registering a user as follows:

CognitoHelper helper = new CognitoHelper();
bool success = await helper.SignUpUser("UserName", "passwword", "userEmail@gmail", "123456789");

  1. The code remains in a deadlock in AmazonCognitoIdentityProviderClient provider =
    new Amazon.CognitoIdentityProvider.AmazonCognitoIdentityProviderClient(new Amazon.Runtime.AnonymousAWSCredentials());.

Logs

Environment

  • Build Version: 2.2.2
  • OS Info: Windows 10 64 bits 20H2
  • Build Environment: Microsoft Visual Studio Community 2019 Versión 16.11.3
  • Targeted .NET Platform: Android 11 (API 30-R)

Resolution

where to create a provider must be as follows: (Obviously the region must be correct)

AmazonCognitoIdentityProviderClient(new Amazon.Runtime.AnonymousAWSCredentials(), RegionEndpoint.YourRegionAWS)


This is a 🐛 bug-report

How to add device to cognito user?

I want to add device to my cognito user. If i set CognitoDevice to cognito user and call RememberThisDeviceAsync on CognitoDevice, i got exception:

Amazon.CognitoIdentityProvider.Model.ResourceNotFoundException: Device does not exist. ---> Amazon.Runtime.Internal.HttpErrorResponseException: Exception of type 'Amazon.Runtime.Internal.HttpErrorResponseException' was thrown.

Expected Behavior

Device must be added to user's devices?

Current Behavior

Exception with following stack trace:

at Amazon.Runtime.Internal.HttpErrorResponseExceptionHandler.HandleException(IExecutionContext executionContext, HttpErrorResponseException exception)
at Amazon.Runtime.Internal.ErrorHandler.ProcessException(IExecutionContext executionContext, Exception exception)
at Amazon.Runtime.Internal.ErrorHandler.d__51.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Amazon.Runtime.Internal.CallbackHandler.<InvokeAsync>d__91.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Amazon.Runtime.Internal.CredentialsRetriever.d__71.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Amazon.Runtime.Internal.RetryHandler.<InvokeAsync>d__101.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Amazon.Runtime.Internal.RetryHandler.d__101.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Amazon.Runtime.Internal.CallbackHandler.<InvokeAsync>d__91.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Amazon.Runtime.Internal.CallbackHandler.d__91.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Amazon.Runtime.Internal.ErrorCallbackHandler.<InvokeAsync>d__51.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Amazon.Runtime.Internal.MetricsHandler.d__1`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---

Possible Solution

Steps to Reproduce (for bugs)

Try this code

var currentUser = m_cognitoUserPool.GetUser("user_email");
var authRequest = new InitiateSrpAuthRequest {
    Password = password
};

var authResponse = await CurrentUser.StartWithSrpAuthAsync(authRequest);

CurrentUser.Device = new CognitoDevice("win_234124", new Dictionary<string, string>(), DateTime.Now, DateTime.Now, DateTime.Now, CurrentUser);
await CurrentUser.Device.RememberThisDeviceAsync();

Your Environment

  • AWSSDK.Core: 3.3.24.4
  • AWSSDK.Extensions.CognitoAuthentication: 0.9.4
  • Operating System and version: Windows 10 17134.165
  • Visual Studio version: Community 2017 15.7.6
  • Targeted .NET platform: Microsoft.NETCore.UniversalWindowsPlatform 5.4.0

StartWithSrpAuthAsync() can throw PasswordResetRequiredException() on login

The Amazon.Extensions.CognitoAuthentication.CognitoUser will throw a PasswordResetRequiredException on login if the user's password has been reset in Cognito. It is not possible to start the ResponseToNewPasswordRequiredAsync() as there's no SessionID available yet (as an exception was thrown, rather than returned on the Task).

Expected Behavior

The exception should be suppressed and the ChallengeName property set to ChallengeNameType.NEW_PASSWORD_REQUIRED.

Current Behavior

PasswordResetRequiredException is thrown.

Steps to Reproduce (for bugs)

Reset the Cognito user's password via AWS Cognito so it must be changed on next login, then attempt login.

Your Environment

AWSSDK.Core v4.0.30319
AWSSDK.Extensions.CognitoAuthentication v4.0.30319

Cognito StartWithRefreshTokenAuthAsync does not respect client secret

Problem

When using refresh token to authenticate against a client that has clientSecret, it throws exception Unable to verify secret hash for client

Sample code

var userPool = new CognitoUserPool(_cognitoOptions.UserPoolId, _cognitoOptions.ClientId, _cognitoClient, _cognitoOptions.ClientSecret);
            var user = new CognitoUser(credentials.UserName, _cognitoOptions.ClientId, userPool, _cognitoClient, _cognitoOptions.ClientSecret);

            // need to manually create a SessionTokens object and add refresh token in
            user.SessionTokens = new CognitoUserSession(null, null, credentials.RefreshToken, DateTime.UtcNow, DateTime.UtcNow.AddHours(1));

            var refreshRequest = new InitiateRefreshTokenAuthRequest()
            {
                AuthFlowType = AuthFlowType.REFRESH_TOKEN_AUTH
            };
            var response = await 
            user.StartWithRefreshTokenAuthAsync(refreshRequest).ConfigureAwait(false);
...

Analysis

When authenticating using password, the SecretHash property is generated and will be used in further validation.

private RespondToAuthChallengeRequest CreateSrpPasswordVerifierAuthRequest(InitiateAuthResponse challenge,
                                                                                   string password,
                                                                                   Tuple<BigInteger, BigInteger> tupleAa)
        {
...
            if (!string.IsNullOrEmpty(ClientSecret))
            {
                SecretHash = CognitoAuthHelper.GetUserPoolSecretHash(Username, ClientID, ClientSecret);
                srpAuthResponses.Add(CognitoConstants.ChlgParamSecretHash, SecretHash);
            }
...

However when authenticating using refresh token, the SecretHash is never created.

private InitiateAuthRequest CreateRefreshTokenAuthRequest(AuthFlowType authFlowType)
        {
...
            if (!string.IsNullOrEmpty(SecretHash))
            {
                initiateAuthRequest.AuthParameters.Add(CognitoConstants.ChlgParamSecretHash, SecretHash);
            }
...

"No such host is known" on login/registration

Hi I'm attempting to setup Cognito authentication in a .NET Core project and whenever a request is made to AWS I get this "No such host is known" exception. I even get this same exception when using the sample project. Please see below for the console output and stack trace:

info: AWSSDK[0]
      Found AWS options in IConfiguration
info: AWSSDK[0]
      Found credentials using the AWS SDK's default credential search
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
System.Net.Http.HttpRequestException: No such host is known.
 ---> System.Net.Sockets.SocketException (11001): No such host is known.
   at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)   at System.Net.Http.DiagnosticsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at Amazon.Runtime.HttpWebRequestMessage.GetResponseAsync(CancellationToken cancellationToken)
   at Amazon.Runtime.Internal.HttpHandler`1.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.Unmarshaller.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.ErrorHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.CallbackHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.EndpointDiscoveryHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.EndpointDiscoveryHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.CredentialsRetriever.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.RetryHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.RetryHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.CallbackHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.CallbackHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.ErrorCallbackHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Runtime.Internal.MetricsHandler.InvokeAsync[T](IExecutionContext executionContext)
   at Amazon.Extensions.CognitoAuthentication.CognitoUserPool.FindByIdAsync(String userID)
   at Amazon.AspNetCore.Identity.Cognito.CognitoUserStore`1.FindByIdAsync(String userId, CancellationToken cancellationToken)
   at Amazon.AspNetCore.Identity.Cognito.CognitoUserManager`1.FindByIdAsync(String userId)
   at Amazon.AspNetCore.Identity.Cognito.CognitoSignInManager`1.PasswordSignInAsync(String userId, String password, Boolean isPersistent, Boolean lockoutOnFailure)
   at MyApp.Areas.Identity.Pages.Account.LoginModel.OnPostAsync(String returnUrl) in C:\Users\user\source\repos\MyApp\MyApp\Areas\Identity\Pages\Account\Login.cshtml.cs:line 74
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory.GenericTaskHandlerMethod.Convert[T](Object taskAsObject)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory.GenericTaskHandlerMethod.Execute(Object receiver, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeHandlerMethodAsync()
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeNextPageFilterAsync()
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Rethrow(PageHandlerExecutedContext context)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeInnerFilterAsync()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)

Version 2.4.1 throws MissingMethodException when used with SignInManager

Describe the bug

Upgrading from 2.4.0 to 2.4.1 starts producing the following error when trying to sign in via password (see await _signInManager.PasswordSignInAsync in the code snippet below).

Expected Behavior

PasswordSignInAsync works as it did in version 2.4.0 or creates a compile-time error exposed to me with the changes needed to upgrade the package.

Current Behavior

I get this stack trace when running the code:

System.MissingMethodException: Method not found: 'System.Threading.Tasks.Task`1<Amazon.Extensions.CognitoAuthentication.CognitoUser> Amazon.Extensions.CognitoAuthentication.CognitoUserPool.FindByIdAsync(System.String)'.\n   at Amazon.AspNetCore.Identity.Cognito.CognitoUserStore`1.FindByIdAsync(String userId, CancellationToken cancellationToken)\n   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)\n   at Amazon.AspNetCore.Identity.Cognito.CognitoUserStore`1.FindByIdAsync(String userId, CancellationToken cancellationToken)\n   at Amazon.AspNetCore.Identity.Cognito.CognitoUserManager`1.FindByIdAsync(String userId)\n   at Amazon.AspNetCore.Identity.Cognito.CognitoSignInManager`1.PasswordSignInAsync(String userId, String password, Boolean isPersistent, Boolean lockoutOnFailure)\n   at Mojo.Server.Admin.Areas.Account.Pages.LoginModel.OnPostAsync(String returnUrl) in /Users/Project/Areas/Account/Pages/Login.cshtml.cs:line 38\n  at
...

Reproduction Steps

Code that calls the SignInManager looks like:

    public class LoginModel : PageModel
    {
        private readonly SignInManager<CognitoUser> _signInManager;
        public LoginModel(SignInManager<CognitoUser> signInManager) => _signInManager = signInManager;

        [Required, Core.Infrastructure.Attributes.EmailAddress, DataType(DataType.EmailAddress), Display(Name = "Email")]
        public string Email { get; set; }

        [Required, DataType(DataType.Password), Display(Name = "Password")]
        public string Password { get; set; }

        public bool RememberMe { get; set; }

        public async Task<IActionResult> OnPostAsync(string returnUrl = null)
        {
            if (ModelState.IsValid)
            {
                returnUrl ??= Url.Content("~/");
                var result = await _signInManager.PasswordSignInAsync(Email, Password, RememberMe, lockoutOnFailure: false);
                if (result.Succeeded)
                {
                    return LocalRedirect(returnUrl);
                }

                if (result.RequiresTwoFactor)
                {
                    return RedirectToPage("Login2FA", new { RememberMe, returnUrl });
                }

                if (result.IsCognitoSignInResult() && result is CognitoSignInResult cognitoResult)
                {
                    if (cognitoResult.RequiresPasswordChange)
                    {
                        return RedirectToPage("ChangePassword", new { returnUrl });
                    }

                    if (cognitoResult.RequiresPasswordReset)
                    {
                        return RedirectToPage("ResetPassword", new { returnUrl });
                    }
                }

                ModelState.AddModelError(string.Empty, "Invalid login");
            }

            return Page();
        }
    }

Possible Solution

Looks like this commit that changed the call signatures with CancellationToken support is what broke this: 8ac3dd9

Additional Information/Context

No response

AWS .NET SDK and/or Package version used

Installed implicitly as dependencies of Amazon.Extensions.CognitoAuthentication 2.4.1
AWSSDK.CognitoIdentity 3.7.0.2
AWSSDK.CognitoIdentityProvider 3.7.0.2

Targeted .NET Platform

.NET 6

Operating System and version

OSX Ventura 13.2

Not able to get any OAuth or custom Scopes in Access Token

Hello:

I am writing an application using Vue as the frontend, and asp.net core web api as the backend.
I am using "Authorization code grant" only for now, will add PKCE later.

Yet the only scope I am able get from the returned access token is "aws.cognito.signin.user.admin"

Below is content is the Access Content Payload, replaced some info with ****

{
  "sub": "*************************",
  "device_key": "*************************",
  "cognito:groups": [
    "AIS_Test_Group"
  ],
  "iss": "https://cognito-idp.ap-southeast-1.amazonaws.com/*****************",
  "client_id": "*************************",
  "event_id": "bcc3b362-ed43-4551-a562-6671f2ec3f2f",
  "token_use": "access",
  "scope": "aws.cognito.signin.user.admin",
  "auth_time": 1564057907,
  "exp": 1564061507,
  "iat": 1564057907,
  "jti": "e68c081c-533e-4f57-88cd-263b06d752f7",
  "username": "hans"
}

Allowed OAuth Scopes is checked for "phone", "email", "openid", "aws.cognito.signin.user.admin" and "profile" in App client settings for uesr pool.

For backend Web API we are using Authenticating with Secure Remote Protocol (SRP)

[HttpPost]
        [Route("SignInSPR")]
        public async Task<ActionResult<string>> SignInSPR(User user)
        {
            var provider = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials(),_region);
            var userPool = new CognitoUserPool(_AWS_UserPoolId, _appClientId, provider);
            var cognitoUser = new CognitoUser(user.Username, _appClientId, userPool, provider);

            AuthFlowResponse authResponse=null;
            authResponse = await cognitoUser.StartWithSrpAuthAsync(new InitiateSrpAuthRequest()
            {
                Password = user.Password
            }).ConfigureAwait(false);

            return Ok(authResponse);
        }

Yet, we are not able to get any OAuth scopes such as "openid" and "profile", or any "custom scopes"

Please advice on how can we get "OAuth scope" and "custom scopes" Amazon Cognito Authentication Extension Library or do I need to use ASP.NET Core Identity Provider?

Thank

Hans

DEVICE_PASSWORD_VERIFIER - NotAuthorizedException: Incorrect username or password

Description

Using v2.2.1 of aws-sdk-net-extensions-cognito and attempting to auth using remembered device results in NotAuthorizedException: Incorrect username or password error, at DEVICE_PASSWORD_VERIFIER code segment in CognitoUserAuthentication.cs

Reproduction Steps

  1. Basic login using user credentials

  2. DeviceSecretVerifierConfigType deviceSecretVerifierConfig = user.GenerateDeviceVerifier(deviceGroupKey, devicePass, username);

  3. await user.ConfirmDeviceAsync(accessToken, deviceKey, deviceName, deviceSecretVerifierConfig.PasswordVerifier, deviceSecretVerifierConfig.Salt).ConfigureAwait(false); (returns OK)

  4. CognitoDevice device = new CognitoDevice(new Amazon.CognitoIdentityProvider.Model.DeviceType()
    {
    DeviceKey = deviceKey
    }, user);
    user.Device = device;
    InitiateSrpAuthRequest authRequest = new InitiateSrpAuthRequest()
    {
    Password = password,
    DeviceGroupKey =deviceGroupKey,
    DevicePass = devicePass,
    };
    AuthFlowResponse authResponse = await user.StartWithSrpAuthAsync(authRequest).ConfigureAwait(false);

    which internally calls GetDeviceAuthenticationKey() in AuthenticationHelper.AuthenticateDevice()

  5. Returns NotAuthorizedException: Incorrect username or password error

Environment

  • Build Version: v2.2.1
  • OS Info: Windows 10
  • Build Environment: Visual Studio 2019 + Unity 2021
  • Targeted .NET Platform: .NET 4.0

Resolution

  1. Use deviceKey instead of Username when calling user.GenerateDeviceVerifier()
  2. Use deviceKey instead of Username when internally calling GetDeviceAuthenticationKey in AuthenticationHelper.AuthenticateDevice()

Correct syntax example :
DeviceAuthIssue1

Aws cognito refresh problem

Hi, I try to refresh aws cognito token by using your code example. But refresh token got null value, and after one hour access token expire as usual.
So kindly how i can refresh token so that access id will not expire up to 30 days

RespondToNewPasswordRequiredRequest returns "Invalid attributes given, name is missing"

Hello,
I'm trying to authenticate with an existing user, that has to update his password, so I started with this:

AuthFlowResponse context = await user.StartWithSrpAuthAsync(new InitiateSrpAuthRequest()
{
	Password = "mypassword"
}).ConfigureAwait(false);

And after context.ChallengeName == ChallengeNameType.NEW_PASSWORD_REQUIRED I tried to update it this way:

    public async Task<bool> UpdatePassword(string username, string newPassword, string sessionId)
    {
        try
        {
            using (var client = new AmazonCognitoIdentityProviderClient(new AnonymousAWSCredentials(), RegionEndpoint.EUCentral1))
            {
                var userPool = new CognitoUserPool(PoolId, ClientId, client, "xxx");
                var user = new CognitoUser(username, ClientId, userPool, client, "xxx");

                var res = await user.RespondToNewPasswordRequiredAsync(new RespondToNewPasswordRequiredRequest
                {
                    SessionID = sessionId,
                    NewPassword = newPassword,
                    
                }).ConfigureAwait(false);

                return true;
            }
		}
		catch (Exception e)
		{
			Console.WriteLine($"UpdatePassword() threw an exception {e}");
		}
        return false;			
	}

The exception was:

Amazon.CognitoIdentityProvider.Model.InvalidParameterException: Invalid attributes given, name is missing

How to solve this? I already tried playing around with AuthFlowResponse.ChallengeParameters, but either this function has a bug or the docs are poor.

Include pdb and xml in NuGet package

Describe the feature

The NuGet packages for the standard AWS SDK include pdb and xml files.
Doing the same for these extensions would be nice... but it's not urgent, since this is a small open source project.

Use Case

Debug and documentation support for programmers using NuGet dll.

Proposed Solution

Follow the same NuGet package creation process as the standard AWS SDKs.

Other Information

No response

Acknowledgements

  • I may be able to implement this feature request
  • This feature might incur a breaking change

AWS .NET SDK and/or Package version used

AWS SDK Extensions for .NET Standard 2.0 (compatible with .NET Framework 4.5)
Version 2.4.1

Targeted .NET Platform

.NET Framework 4.5

Operating System and version

Ubuntu 22.04

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.