Using Drop-in resulting in CORS error

Hey Dwolla Team!

I’m using the “dwolla-customer-create” drop in to create a new customer. Configuration is as follows:

dwolla.configure({
    environment: "sandbox",
    tokenUrl: "https://bv2kys09u8.execute-api.us-west-2.amazonaws.com/Production/dwolla",
    success: (res) => Promise.resolve(res),
    error: (err) => Promise.resolve(err),
});

The issue I’m facing is that when I make the call to a Restful API on AWS"s Gateway API Platform to reach the lambda on the backend running dwollav2 on python it keeps throwing CORS errors:

Access to fetch at 'https://bv2kys09u8.execute-api.us-west-2.amazonaws.com/Production/dwolla' from origin 'https://www.yourlandloans.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'.

I was able to overcome the first CORS error but this one is where I’m running into issues. It appears the Drop-in is passing “Access-Control-Allow-Credentials: true” but I don’t see a way to pass my authentication token along with the call? I’ve disabled authentication on this API for testing but no luck. Tests from postman (with auth disabled) work great so it does appear it is likely a CORS related issue.

Any advice would be greatly appreciated. Thanks

Hi JT!

Hmm…the only thing I can think of is that your AWS endpoint is probably can’t be reached via the client-side. Since calls from Postman are working fine, I would assume that if calls are made to that endpoint from the server-side of your application, that they would go through.

Perhaps you could have a function in your app’s server-side (like in this example) that calls the AWS lambda to generate client-tokens, and then you would set your tokenUrl key in the above configuration to that server-side URL you created in your app (example here).

dwolla.configure({
    environment: "sandbox",
    tokenUrl: "your_server_side_url",
    success: (res) => Promise.resolve(res),
    error: (err) => Promise.resolve(err),
});

Not sure if that helps, but please let us know if you have any questions!

Hey @shreya !

Thanks for taking the time to respond back to me. I feel like there’s some component of this that I’m not understanding. I’ve reviewed everything I can find on the subject across all these locations:

https://docs.dwolla.com/#drop-in-components
https://developers.dwolla.com/guides/drop-ins#building-with-drop-in-components
https://developers.dwolla.com/concepts/drop-in-components#ui-components-library

Etc.

This is how my flow is setup:
(Front End) Drop-In “dwolla-customer-create” →
AWS API Gateway “https://bv2kys09u8.execute-api.us-west-2.amazonaws.com/Production/dwolla” →
Lambda (dwollav2-python) →

import dwollav2
import os

# Create dwolla client object
client = dwollav2.Client(
  key = os.environ['dwolla_sandbox_api_key'],
  secret = os.environ['dwolla_sandbox_api_secret'],
  environment = 'sandbox', # defaults to 'production'
)

# Application Token
app_token = client.Auth.client()

# Create a new client
def create_new_client_token():
    request_body = {
      'action': 'customer.create'
    }
    
    client_token = app_token.post('client-tokens', request_body)
    return client_token.body['token'] # => '4adF858jPeQ9RnojMHdqSD2KwsvmhO7Ti7cI5woOiBGCpH5krY'

def lambda_handler(event, context):
    if event['action'] == 'customer.create':
        new_client_token = create_new_client_token()
        return {
            'statusCode': 200,
            'body': {'token': new_client_token}
        }

Dwolla (For Client Token)

Testing this works great except for the Drop-In reaching the API Gateway (seemingly due to CORS). Is the the Drop-In not supposed to reach to the backend via an API for the token via the “TokenUrl” value? Frankly, I’m a little confused by what y’all mean by “/tokenUrl”. Would you mind providing me an example there?

Obviously, a bit befuddled here. Thanks again!

So I was able to work around this for now by forcing the API to respond with a "Access-Control-Allow-Credentials: ‘true’ " So that’s good! However, this is far from optimal since I now have an API that requires no authentication to call that creates Client-Tokens and hands them out to whoever Willy-Nilly. Is there any way to pass the end customers JWT to the Drop-In so that it can be used to authenticate against the API?

Thanks!

@shreya @kmoreira

Any assistance with regard to the above question about passing some kind of JWT to the Drop-ins for the necessary API calls when obtaining Client-Tokens?

Thanks!

Hi @YourLandLoans!

I circled up with our dev team and found the following that might help!

You could override our current token handling by using the token function. So, instead of calling configure like this:

    <script>
        dwolla.configure({
            environment: "sandbox",
            // styles: "/styles/create-custom.css",
            tokenUrl: "/tokenUrl",
            success: (res) => Promise.resolve(),
            error: (err) => Promise.resolve(),
        });
    </script>

you could call:

    <script>
        dwolla.configure({
            environment: "sandbox",
            // styles: "/styles/create-custom.css",
            success: (res) => Promise.resolve(),
            error: (err) => Promise.resolve(),
            token: (req) => Promise.resolve(dwollaAPIToken(req, {blah: "abcd"}))
        });
    </script>

This would allow you to set up a function that can pass through custom headers:

function dwollaAPIToken(req, additional) {
  console.log("req.action: ", req.action);
  console.log("req.links: ", req.links);
  const tokenUrl = "/tokenUrl";
  const data = {
    action: req.action,
  };
  if (req.links) {
    data._links = req.links;
  }
  const headers = {
    Accept: "application/json",
    "Content-Type": "application/json",
    "X-Requested-With": "Dwolla-Drop-Ins-Library",
  };
  return fetch(`${tokenUrl}`, {
    credentials: "include",
    method: "POST",
    body: JSON.stringify(data),
    headers,
  })
    .then((response) => {
      return response.json();
    })
    .then((result) => {
      return result;
    })
    .catch((error) => {
      console.log(error);
      return error;
    });
}

Ahh, that will be great! Thank you much.

1 Like