1

I have ASP.Net MVC5 website where I trying to accept a payment via PayPal.

The user case is that a member logs-in and views his/her account. If they have an outstanding balance then they click a 'make payment' button which takes them to a page that accepts an amount. Submitting the form on this page redirects them to PayPal (sandbox environment) to complete the payment.

My problem is that once the payment is completed in PayPal, the user has to login again.

I have been using this tutorial as a guide. I don't have a shopping cart so I have ignored the first part of the tutorial and moved straight to the Integrating PayPal section (I didn't see anything that I thought was relevant to make authentication issue, but I could be wrong).

The ShortcutExpressCheckout method correctly returns the required URL (and token). I build the return URL using the following (subPath is {controller}/{action}):

    private string GetAbsolulteUrl(string subPath)
    {
        var appPath = string.Format("{0}://{1}{2}", Request.Url.Scheme, Request.Url.Authority, Url.Content("~"));
        var baseUri = new Uri(appPath);
        var uri = new Uri(baseUri, subPath);

        return uri.AbsoluteUri;
    }

I then use Response.Redirect, which goes off to PayPal.

Once the payment is completed the browser's URL is redirected to:

http://{my app's login page}?ReturnUrl={subPath}%26token{token}

I don't know if this issue is happening because I'm using IIS Express for development. That is, is IIS Express is throwing away all session info when it is redirected to PayPal?

Assuming IIS Express is not the problem, does anyone know how to retain credentials when returning from PayPal?

UPDATE:

It must be something with our software because I downloaded the source from tutorial and ran it and it works fine, even with with IIS Express (and they the tutorial code has authentication as well).

We have two websites; an MVC Razor website and a Web API website that handles the authentication.

When I login at the start, the request sent to the token authorisation controller in the API has a token that looks like this:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJNUCIsImF1ZCI6Imh0dHBzOi8vbG9jYWxob3N0OjQ0MzAxLyIsIm5iZiI6MTQwODQ5MzIwMCwiZXhwIjoxNDA4NTM2NDAwLCJuYW1laWQiOiIxMjEzIiwiY2x1YmlkIjoiNTAwNTIiLCJtZW1iZXJpZCI6IjIiLCJhdXRobWV0aG9kIjoicmVzb3VyY2Vvd25lciIsImp0aSI6IjU3Yjc5Yjk2LTlhNzgtNGM5Yy1hNDI2LWQ1OGZlYmM5OWJkNSJ9.rPPFyStZzwy0dRwczU2w4pzmRezgIsDX2VO9lArU15A

Every request passes this token around.

When returning from PayPal the token looks like this:

EC-2JD43180AM571484F

And, this invalid token causes the following exception.

System.ArgumentException was caught
  HResult=-2147024809
  Message=Jwt10204: 'System.IdentityModel.Tokens.JwtSecurityTokenHandler' cannot read this string: 'EC-2R2454574X846761Y'.
The string needs to be in compact JSON format, which is of the form: '<Base64UrlEncodedHeader>.<Base64UrlEndcodedPayload>.<OPTIONAL, Base64UrlEncodedSignature>'.
  Source=System.IdentityModel.Tokens.Jwt
  StackTrace:
       at System.IdentityModel.Tokens.JwtSecurityTokenHandler.ReadToken(String jwtEncodedString)
       at {our namespace}.Providers.JwtTokenServiceProvider.GetToken(String value)
       at {our namespace}.TokenAuthorisationController.Post(TokenRequest request)

UPDATE 2:

Tutorial authentication configuration code:

    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login")
        });

        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
        app.UseGoogleAuthentication();
    }

Our authentication configuration:

    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login")
        });

        app.UseTokenAuthentication(new TokenAuthenticationOptions());
    }

They use external cookie and we use token authentication.

UPDATE 3:

Ok, it turns out that we have a TokenAuthenticationHandler class intercepts requests and checks to see if the there is URL query parameter called "token" and uses that for authentication before it checks the request header.

So I got the token out of the claims principal and put it in the PayPal return URL and a query parameter.

However, I think get the an exception message that says:

The string needs to be in compact JSON format, which is of the form: '<Base64UrlEncodedHeader>.<Base64UrlEndcodedPayload>.<OPTIONAL, Base64UrlEncodedSignature>'.

Does anyone know how to properly encode my token so it can be used as a query parameter?

TheMagnificent11
  • 1,424
  • 4
  • 19
  • 40

1 Answers1

0

Wrote a TokenAuthenticationHandler class that inherits AuthenticationHandler.

That allowed me to intercept the redirect from PayPal and extract the token from the URL query parameter.

I'm still getting the same exception but all in need to solve now is JSON formatting/URL encoding.

I've posted another question about this here.

Community
  • 1
  • 1
TheMagnificent11
  • 1,424
  • 4
  • 19
  • 40