Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Authentication Settings for Amazon and Evernote

If you refer to https://docs.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x?view=aspnetcore-2.2 you can see you can configure OpenID Connect (OIDC) authentication for various providers as below:

Facebook

services.AddAuthentication()
        .AddFacebook(options =>
        {
            options.AppId = Configuration["auth:facebook:appid"];
            options.AppSecret = Configuration["auth:facebook:appsecret"];
        });

Google

services.AddAuthentication()
        .AddGoogle(options =>
        {
            options.ClientId = Configuration["auth:google:clientid"];
            options.ClientSecret = Configuration["auth:google:clientsecret"];
        });

Microsoft

services.AddAuthentication()
        .AddMicrosoftAccount(options =>
        {
            options.ClientId = Configuration["auth:microsoft:clientid"];
            options.ClientSecret = Configuration["auth:microsoft:clientsecret"];
        });

My question is does anybody have the settings I would need to provide to Support Amazon and Evernote OIDC?

like image 386
Jim Culverwell Avatar asked Apr 18 '19 02:04

Jim Culverwell


People also ask

How do I set up two factor authentication on Amazon?

To enable Two-Step Verification:In Your Account, select Login & security. Select Edit beside Two-Step Verification (2SV) Settings. Click Get Started. Follow the on-screen instructions.

How do I set up OTP on Amazon?

Choose Login & Security Click Edit next to Two-Step Verification (2SV) Settings. In the Enrolled 2SV Authenticators section, click Add new phone or Authenticator App. Complete two-step verification by receiving an OTP via voice call. Enter the OTP you received and the Add backup method page will open.


Video Answer


3 Answers

You can find Login with Amazon reference here
Amazon still does not support OIDC, but supports OAuth. However the default OAuthHandler for dotnet does not provide UserInfoEndpoint handling. That's why you have to either implement the call to UserInfoEndpoint (can grab it from oidc) or hack the OIDC to make it thinking that it has id_token whenever it has not. I've passed the second route. Little bit dirty trick, but I've got my user identified.

.AddOpenIdConnect("lwa", "LoginWithAmazon", options =>
{
  options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
  options.SignOutScheme = IdentityServerConstants.SignoutScheme;

  options.Authority = "https://www.amazon.com/";
  options.ClientId = "amzn1.application-oa2-client.xxxxxxxxxxxxxx";
  options.ClientSecret = "xxxxxxxxxxxxxxxxx";
  options.ResponseType = "code";
  options.ResponseMode = "query";
  options.SaveTokens = true;
  options.CallbackPath = "/signin-amazon";
  options.SignedOutCallbackPath = "/signout-callback-amazon";
  options.RemoteSignOutPath = "/signout-amazon";
  options.Scope.Clear();
  options.Scope.Add("profile");
  options.GetClaimsFromUserInfoEndpoint = true;

  var rsa = RSA.Create();
  var key = new RsaSecurityKey(rsa){KeyId = "1"};

  var jwtClaims = new List<Claim>
                    {
                        new Claim(JwtClaimTypes.IssuedAt, "now"),
                        new Claim(JwtClaimTypes.JwtId, Guid.NewGuid().ToString()),
                        new Claim(JwtClaimTypes.Subject, Guid.NewGuid().ToString())
                    };

  var jwt = new JwtSecurityToken(
                    "issuer",
                    "audience",
                    jwtClaims,
                    DateTime.UtcNow,
                    DateTime.UtcNow.AddHours(1),
                    new SigningCredentials(key, "RS256"));

  var handler = new JwtSecurityTokenHandler();
  handler.OutboundClaimTypeMap.Clear();
  var token = handler.WriteToken(jwt);

  options.Configuration = new OpenIdConnectConfiguration
  {
      AuthorizationEndpoint = "https://www.amazon.com/ap/oa",
      TokenEndpoint = "https://api.amazon.com/auth/o2/token",
      UserInfoEndpoint = "https://api.amazon.com/user/profile"
  };

  options.TokenValidationParameters = new TokenValidationParameters
  {
      ValidateTokenReplay = false,
      ValidateIssuer = false,
      ValidateAudience = false,
      ValidateLifetime = false,
      IssuerSigningKey = key
  };

  AuthorizationCodeReceivedContext hook = null;
  options.Events = new OpenIdConnectEvents
  {
       OnAuthenticationFailed = async context =>
       {
           //context.SkipHandler();
       },
       OnAuthorizationCodeReceived = async context => { hook = context; },
       OnTokenResponseReceived = async context =>
       {
           context.TokenEndpointResponse.IdToken = token;
           hook.TokenEndpointResponse = context.TokenEndpointResponse;
       },
       OnUserInformationReceived = async context =>
       {
           var user = context.User;
           var claims = new[]
           {
               new Claim(JwtClaimTypes.Subject, user["user_id"].ToString()),
               new Claim(JwtClaimTypes.Email, user["email"].ToString()),
               new Claim(JwtClaimTypes.Name, user["name"].ToString())
           };
           context.Principal = new ClaimsPrincipal(new ClaimsIdentity(claims));
           context.Success();
       }
  };
})
like image 147
d_f Avatar answered Sep 24 '22 13:09

d_f


Unfortunately, neither Login with Amazon nor Evernote supports Open ID Connect. Other mentioned services do, which can be verified by visiting appropriate configuration site of each of them: Google, Microsoft.

There are ofc others that are not preconfigured in .Net and can be used with it: Salesforce

As you probably noticed usually the configuration for Open ID Connect is stored on a site with "/.well-known/openid-configuration" suffix. This is called OpenID Connect metadata document and it contains most of the information required for an app to do sign-in. This includes information such as the URLs to use and the location of the service's public signing keys.

And now lets go for .Net configuration for custom Open ID Connect provider (I will use Salesforce as it supports Open ID):

services.AddAuthentication()
.AddFacebook(options =>
{
    options.AppId = Configuration["auth:facebook:appid"];
    options.AppSecret = Configuration["auth:facebook:appsecret"];
})
.AddOpenIdConnect("OpenIdConnectSalesforce", "Salesforce", options =>
{
    options.Authority = "https://login.salesforce.com";
    options.ClientId = Configuration["auth:salesforce:appid"];
    options.ClientSecret = Configuration["auth:salesforce:appsecret"];
    options.ResponseType = "code";
});

And after launching web app we can see additional button to log in using Salesforce: enter image description here

As for Evernote and Amazon you could use their SDKs and APIs to implement their log in methods respectively. I do believe that they support OAuth.

like image 36
Lesmian Avatar answered Sep 23 '22 13:09

Lesmian


Extended the solution by @d-f to use OAuth handler.

.AddOAuth("lwa-oauth", "OauthLoginWithAmazon", options =>
{
    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

    options.ClientId = "amzn1.application-oa2-client.zzzzzzzzzzzz";
    options.ClientSecret = "4c0630b4166c901519a730835ezzzzzzzzzzzzzzzz";
    options.SaveTokens = true;
    options.CallbackPath = "/signin-amazon";
    options.Scope.Clear();
    options.Scope.Add("profile");

    options.AuthorizationEndpoint = "https://www.amazon.com/ap/oa";
    options.TokenEndpoint = "https://api.amazon.com/auth/o2/token";
    options.UserInformationEndpoint = "https://api.amazon.com/user/profile";

    options.Events = new OAuthEvents
    {
         OnCreatingTicket = async context =>
         {
            var accessToken = context.AccessToken;
            HttpResponseMessage responseMessage = 
                 await context.Backchannel.SendAsync(
                        new HttpRequestMessage(HttpMethod.Get, options.UserInformationEndpoint)
            {
              Headers = 
              {
                    Authorization = new AuthenticationHeaderValue("Bearer", accessToken)
              }
            });
            responseMessage.EnsureSuccessStatusCode();
            string userInfoResponse = await responseMessage.Content.ReadAsStringAsync();
            var user = JObject.Parse(userInfoResponse);
            var claims = new[]
            {
              new Claim(JwtClaimTypes.Subject, user["user_id"].ToString()),
              new Claim(JwtClaimTypes.Email, user["email"].ToString()),
              new Claim(JwtClaimTypes.Name, user["name"].ToString())
            };
            context.Principal = new ClaimsPrincipal(new ClaimsIdentity(claims));
            context.Success();
       }
   };
})
like image 33
Alla_T Avatar answered Sep 25 '22 13:09

Alla_T