I'm starting to use PayPal for payments with .net Core. I created a sandbox app and checked client id and secret. I get an error at content
"{"error":"invalid_client","error_description":"Client Authentication failed"}"
Code:
private async Task<PayPalAccessToken> GetPayPalAccessTokenAsync(HttpClient httpClient)
{
byte[] bytes = Encoding.GetEncoding("iso-8859-1")
.GetBytes($"{_configuration["PayPal:clientId"]} : {_configuration["PayPal:secret"]}");
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, "/v1/oauth2/token");
requestMessage.Headers.Authorization =
new AuthenticationHeaderValue("Basic", Convert.ToBase64String(bytes));
var form = new Dictionary<string, string>
{
["grant_type"] = "client_credentials"
};
requestMessage.Content = new FormUrlEncodedContent(form);
HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);
string content = await responseMessage.Content.ReadAsStringAsync();
PayPalAccessToken accessToken = JsonConvert.DeserializeObject<PayPalAccessToken>(content);
return accessToken;
}
Setting:
"PayPal": {
"clientId": "xxx",
"secret": "xxx",
"urlAPI": "https://api-m.sandbox.paypal.com",
"returnUrl": "https://localhost:44370/cart/success",
"cancelUrl": "https://localhost:44370/cart/cancel"
}
And here is Code I followed https://gist.github.com/jakejscott/1b829ca1c9449e4788710867f346e90f
Full my code https://paste.mod.gg/ayoqinotis.csharp
What is the problem that I am facing?
Related
I am adding CF Turnstile recaptcha to my asp.net core web api for our contact us form and I am curious what IP address I should be using for this verification process. My code is as follows:
var dictionary = new Dictionary<string, string>
{
{ "secret", reCaptchaKey },
{ "response", customerInquiry.Token }
};
var postContent = new FormUrlEncodedContent(dictionary);
HttpResponseMessage recaptchaResponse = null;
string stringContent = "";
// Call recaptcha api and validate the token
using (var http = new HttpClient())
{
recaptchaResponse = await http.PostAsync("https://challenges.cloudflare.com/turnstile/v0/siteverify", postContent);
stringContent = await recaptchaResponse.Content.ReadAsStringAsync();
}
The example code on CF shows the following for their node.js ( I assume) implementation:
formData.append('secret', SECRET_KEY);
formData.append('response', token);
formData.append('remoteip', ip);
The following .NET Core method returns BadRequest error:invalid_grant
However not always, only in the middle of a session - not sure what else is needed. The request is made from a Blazor App:
private async Task<TokenResponse> RefreshAccessToken()
{
string authority = _configuration.GetValue("Authority", "url...");
using (HttpClient serverClient = _httpClientFactory.CreateClient())
{
var discoveryDocument = await serverClient.GetDiscoveryDocumentAsync(authority);
var refreshToken = _tokenProvider.RefreshToken;
using (HttpClient refreshTokenClient = _httpClientFactory.CreateClient())
{
TokenResponse tokenResponse = await refreshTokenClient.RequestRefreshTokenAsync(
new RefreshTokenRequest
{
Address = discoveryDocument.TokenEndpoint,
RefreshToken = refreshToken,
ClientId = "client id ...",
ClientSecret = "secret ..."
});
return tokenResponse;
}
}
}
This is the request message:
I have an asp.net 4.6 web forms application (no MVC). I am updating the security in my application. I am using OpenIdConnectAuthentication to authenticate with our Azure AD. Then I pass the access token to Microsoft graph to send an email with Office 365. My token is set to expire in 60 minutes. I either need to expand the expiration to 8 hours or refresh the token. Without having MVC I am not sure how to handle this. I am looking for help with direction to take and possibly code samples.
(I original tried to utilize an MVC sample and put it into my project using a Session Token class. Once we tested with multiple users I believe I had a memory leak and it would crash in about 5 minutes.)
Startup code:
public class Startup
{
private readonly string _clientId = ConfigurationManager.AppSettings["ClientId"];
private readonly string _redirectUri = ConfigurationManager.AppSettings["RedirectUri"];
private readonly string _authority = ConfigurationManager.AppSettings["Authority"];
private readonly string _clientSecret = ConfigurationManager.AppSettings["ClientSecret"];
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
CookieManager = new SystemWebCookieManager(),
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = _clientId,
ClientSecret = _clientSecret,
//Authority = _authority,
Authority = String.Format(_authority, domain, "/v2.0"),
RedirectUri = _redirectUri,
ResponseType = OpenIdConnectResponseType.CodeIdToken,
Scope = OpenIdConnectScope.OpenIdProfile,
UseTokenLifetime = false,
TokenValidationParameters = new TokenValidationParameters { NameClaimType = "name", RequireExpirationTime = false},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async n =>
{
// Exchange code for access and ID tokens
var auth = String.Format(_authority, "common/oauth2/v2.0", "/token");
var tokenClient = new TokenClient($"{auth}", _clientId, _clientSecret);
var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(n.Code, _redirectUri);
if (tokenResponse.IsError)
{
throw new Exception(tokenResponse.Error);
}
var claims = new List<Claim>()
{
new Claim("id_token", tokenResponse.IdentityToken),
new Claim("access_token", tokenResponse.AccessToken)
};
n.AuthenticationTicket.Identity.AddClaims(claims);
},
},
});
}
}
SDK Helper:
public class SDKHelper
{
// Get an authenticated Microsoft Graph Service client.
public static GraphServiceClient GetAuthenticatedClient()
{
GraphServiceClient graphClient = new GraphServiceClient(
new DelegateAuthenticationProvider(
async (requestMessage) =>
{
string accessToken = System.Security.Claims.ClaimsPrincipal.Current.FindFirst("access_token").Value;
// Append the access token to the request.
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
// Get event times in the current time zone.
requestMessage.Headers.Add("Prefer", "outlook.timezone=\"" + TimeZoneInfo.Local.Id + "\"");
// This header has been added to identify our sample in the Microsoft Graph service. If extracting this code for your project please remove.
requestMessage.Headers.Add("SampleID", "aspnet-snippets-sample");
}));
return graphClient;
}
}
Sending Email:
GraphServiceClient graphClient = SDKHelper.GetAuthenticatedClient();
string address = emailaddress;
string guid = Guid.NewGuid().ToString();
List<Recipient> recipients = new List<Recipient>();
recipients.Add(new Recipient
{
EmailAddress = new Microsoft.Graph.EmailAddress
{
Address = address
}
});
// Create the message.
Message email = new Message
{
Body = new ItemBody
{
ContentType = Microsoft.Graph.BodyType.Text,
},
Subject = "TEST",
ToRecipients = recipients,
From = new Recipient
{
EmailAddress = new Microsoft.Graph.EmailAddress
{
Address = address
}
}
};
// Send the message.
try
{
graphClient.Me.SendMail(email, true).Request().PostAsync().Wait();
}
catch (ServiceException exMsg)
{
}
You need to request the scope offline_access. Once you've requested that, the /token endpoint will return both an access_token and a refresh_token. When your token expires, you can make another call to the /token endpoint to request a new set of access and refresh tokens.
You might find this article helpful: Microsoft v2 Endpoint Primer. In particular, the section on refresh tokens.
I'm using asp.net boilerplate for my website. There I have standard authentication from aspnetboilerplate/module-zero(OWIN).
But now I need athentication for my windows phone app(wp8.1)
I was trying configure my application for authorization with bearer but I failed..
How configurate asp.net boilerplate application for my windows phone app auth?
In windows phone app I send post to my web api like this:
public static async Task<TokenResponseModel> GetBearerToken(string siteUrl, string Username, string Password)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(siteUrl);
client.DefaultRequestHeaders.Accept.Clear();
HttpContent requestContent = new StringContent("grant_type=password&username=" + Username + "&password=" + Password, Encoding.UTF8, "application/x-www-form-urlencoded");
HttpResponseMessage responseMessage = await client.PostAsync("Token", requestContent);
if (responseMessage.IsSuccessStatusCode)
{
string jsonMessage;
using (Stream responseStream = await responseMessage.Content.ReadAsStreamAsync())
{
jsonMessage = new StreamReader(responseStream).ReadToEnd();
}
TokenResponseModel tokenResponse = (TokenResponseModel)JsonConvert.DeserializeObject(jsonMessage, typeof(TokenResponseModel));
return tokenResponse;
}
else
{
return null;
}
}
But what should I do in WebApi? How auth and next response bearer and how auth in next step using bearer when on class i have [AbpAuthorize]?
This now documented and implemented in module zero template
code:
In module WebApi:
Configuration.Modules.AbpWebApi().HttpConfiguration.Filters.Add(new HostAuthenticationFilter("Bearer"));
In controller WebApi:
[HttpPost]
public async Task<AjaxResponse> Authenticate(LoginModel loginModel)
{
CheckModelState();
var loginResult = await GetLoginResultAsync(
loginModel.UsernameOrEmailAddress,
loginModel.Password,
loginModel.TenancyName
);
var ticket = new AuthenticationTicket(loginResult.Identity, new AuthenticationProperties());
var currentUtc = new SystemClock().UtcNow;
ticket.Properties.IssuedUtc = currentUtc;
ticket.Properties.ExpiresUtc = currentUtc.Add(TimeSpan.FromMinutes(30));
return new AjaxResponse(OAuthBearerOptions.AccessTokenFormat.Protect(ticket));
}
documentation: http://aspnetboilerplate.com/Pages/Documents/Zero/Startup-Template#token-based-authentication
Im trying to secure my ASP.NET web api using OWIN and ASP.NET identity, I managed to get it done. But I am saving the access token in the client's local storage (Mobile) which defeats the purpose of the access token. So I have to add refresh token. I managed to generate the refresh token using the same ticket of the access token. But now I don't know how to use the refresh token in the client.
Startup.cs
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId, UserManagerFactory),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(tokenExpiry),
AllowInsecureHttp = true,
RefreshTokenProvider = new AuthenticationTokenProvider
{
OnCreate = CreateRefreshToken,
OnReceive = ReceiveRefreshToken,
}
};
private static void CreateRefreshToken(AuthenticationTokenCreateContext context)
{
context.SetToken(context.SerializeTicket());
}
private static void ReceiveRefreshToken(AuthenticationTokenReceiveContext context)
{
context.DeserializeTicket(context.Token);
}
AccountController.cs
private JObject GenerateApiToken(IdentityUser user, TimeSpan tokenExpirationTimeSpan, string provider)
{
var identity = new ClaimsIdentity(Startup.OAuthOptions.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, user.Id, null, provider));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id, null, "LOCAL_AUTHORITY"));
var ticket = new AuthenticationTicket(identity, new AuthenticationProperties());
var currentUtc = new Microsoft.Owin.Infrastructure.SystemClock().UtcNow;
ticket.Properties.IssuedUtc = currentUtc;
ticket.Properties.ExpiresUtc = currentUtc.Add(tokenExpirationTimeSpan);
var accesstoken = Startup.OAuthOptions.AccessTokenFormat.Protect(ticket);
var refreshtoken = Startup.OAuthOptions.RefreshTokenFormat.Protect(ticket);
Authentication.SignIn(identity);
// Create the response
JObject blob = new JObject(
new JProperty("userName", user.UserName),
new JProperty("access_token", accesstoken),
new JProperty("refresh_token", refreshtoken),
new JProperty("token_type", "bearer"),
new JProperty("expires_in", tokenExpirationTimeSpan.TotalSeconds.ToString()),
new JProperty(".issued", ticket.Properties.IssuedUtc.ToString()),
new JProperty(".expires", ticket.Properties.ExpiresUtc.ToString())
);
var json = Newtonsoft.Json.JsonConvert.SerializeObject(blob);
return blob;
}
Client request for bearer token
$.ajax({type: 'POST',
url: tokenUrl + "Token",
data: "grant_type=password&username=" + identity.userName + "&password=" + identity.password,
contentType: 'application/x-www-form-urlencoded',
}).
done(function(response) {
app.tokenManager.saveToken(response.access_token, response.refresh_token, response.expires_in, apiTokenType.BASIC);
deferred.resolve({
token: response.access_token
});
})
.fail(function(result, status) {
deferred.reject(result);
});
Now, how can I use the Refresh token?
according to aouth2 spec
https://www.rfc-editor.org/rfc/rfc6749#section-6
try
POST /token HTTP/1.1
Host: server.example.com
Authorization: Bearer czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA