PHP Twilio RequestValidator returning false on all endpoints - twilio

So I really don't know what the problem is here, I've tried many things, but I can't get the Twilio request hashes to match up. Let me explain.
I decided to implement an instance of Twilio's RequestValidator to ensure the requests were coming from Twilio. But after following the tutorial here: https://www.twilio.com/docs/usage/security?code-sample=code-validate-signature-of-request-1&code-language=PHP&code-sdk-version=5.x
The validator is only returning false. Here is the code that I used:
$url = 'https://example.com/api/endpoint/to/endpoint/';
$request_params = $_REQUEST;
$twilio_validator = new RequestValidator('myauthtoken');
if (!$twilio_validator->validate($_SERVER['HTTP_X_TWILIO_SIGNATURE'], $url, $request_params)) {
throw new CallException('Not from Twilio');
}
Even though the URL is an example, that is exactly how I have the actual URL formatted...no port, basic auth, or fragment. Just the protocol, domain, and path with a trailing "/". In addition, the URL is the exact VoiceURL I set when I set up this Twilio App (this is calling the VoiceURL to one of my Twilio Apps).
My auth token is the auth token for my whole account
The request params is where I'm sure I'm messing something up. Twilio is making a GET request to this endpoint, and I tried using the $_GET superglobal as well, to no avail. I'm using $_REQUEST here because of this issue: https://github.com/twilio/twilio-php/issues/510 and because I thought it would be the best choice. I have also tried using file_get_contents('php://input') to the exact same problem (the hashes not matching, ultimately).
I even forked and opened a PR on the PHP SDK to update the class a little bit, just to see if I could learn any more...so I know the class and it's methods pretty well...I just don't see my issue.
What am I doing wrong here to make it so that the RequestValidator isn't validating that the requests from Twilio are coming from Twilio?

So after a lot of research and working with Twilio help, I figured out the answer to my question.
When Twilio is making a GET request to my server, you aren't supposed to pass the GET parameters as the third parameter to the validate method on the RequestValidator class. When Twilio is making a GET request to your server, validating actually needs to look like this:
// this is the interesting part...you don't even set the pathname on the domain...
// EVEN IF YOU THE PATHNAME IS SET IN YOUR VOICE URL.
// This is because of the different way the RequestValidator handles GET and POST params
$domain = 'https://example.com'; // make sure to add no trailing '/'
// setting up the RequestValidator
$twilio_validator = new RequestValidator('myauthtoken');
// figuring out if the request is from twilio
$is_from_twilio = $twilio_validator->validate(
// the signature header that Twilio sends
$_SERVER['HTTP_X_TWILIO_SIGNATURE'],
// The domain name CONCATENATED to the Request URI. $_SERVER['REQUEST_URI'] holds everything that comes after the domain name in a URL (pathname, query parameters, and fragment)
$domain.$_SERVER['REQUEST_URI']
// if the request is a get request, as mine are, there is no need for the third parameter
);
// resolving the response
if (!$is_from_twilio) {
echo 'Not from Twilio';
exit;
}
Refer to the comments in the code for a more in depth discussion on the code at work here..

Related

How to pass dynamic value to JSON as a API request in flutter flow?

I have two page
Login/Registration Page as of now
OTP Verification Page
API has been created and in api, we are passing phone number as request and gets otp as response. However i would like your help to know how should i able to pass the phoneNumber textfield data to APIcall json request in flutterflow?
If there is anyway or any documentation will be really helpful?
I have tried with variable method, however i was not able to pass it to json.
I have also tried jsonpath method, but no luck.
Define dynamic part of API url with brackets
https://jsonplaceholder.typicode.com/posts/[postId]
https://jsonplaceholder.typicode.com/comments?postId=[postId]
then create the variable (postId) with the same name. When adding the API call, it is required to add these variables.
See API Calls 101 for details.

Run a flow from another flow in Twilio

How can I run a flow from another flow in Twilio Studio Flow?
Help with defining the To and From HTTP parameters:
I am a beginner in programming so I am failing to understand the brief notes given in support docs, namely specifying HTTP additional parameters for "To" and "From".
Additional details from comment:
I am trying to run REST API triggered Flow B from primary Flow A by using an http request widget in Flow A in the format below: (as suggested in a similar problem posted on this portal) Widget: HTTP Request [ACCOUNT_SID:AUTH_TOKEN#studio.twilio.com/v1/Flows/THE_OTHER_STUDIO_FLOW_SID/Executions][2] Content Type: Form URL Encoded KEY:VALUES To:+1234567890 From:+2773123456 I am getting error 401. I tried to swap the To number with the From number without success
There are 2 ways you can trigger one twilio studio flow from another
Method 1:
Use the TwiML Redirect Widget. Place the widget where you need it and specify the target studio flow URL there. Studio URLs have the following format
https://webhooks.twilio.com/v1/Accounts/{AccountSid}/Flows/{FlowSid}
Method 2:
Do the same as above programmatically. You can send twilio a twiML response such as the one below
let twiml = new Twilio.twiml.VoiceResponse();
if (something) {
twiml.redirect({
method: 'POST'
}, 'https://webhooks.twilio.com/v1/Accounts/{AccountSid}/Flows/{FlowSid1}');
} else {
twiml.redirect({
method: 'POST'
}, 'https://webhooks.twilio.com/v1/Accounts/{AccountSid}/Flows/{FlowSid2}');
}
For more info, check out https://www.twilio.com/docs/voice/twiml/redirect
Assuming you are not trying to bridge the call between the two flows, this should be possible. To simplify:
You have a call come in on Flow A ("Incoming Call" trigger on Flow A).
Flow A executes its logic.
That logic triggers Flow B by calling its REST API endpoint so that it makes a new outbound call ("REST API" trigger on Flow B).
This last thing is the hard part. Make sure you are looking at the docs for the REST API Execution resource. To trigger a new flow, you need to make a POST request which supplies the To and From parameters.
If you are a beginner at programming, it might be helpful for you to start with a separate HTTP client like Postman to start to get familiar with the structure of an HTTP request, and learn the full extent of what is required to successfully make this API request before you start trying to cram it into Studio and automate it.
That said, this request should be possible to do within the Studio Make HTTP Request widget. If you make your content type Application/JSON, you can pass the To/From parameters directly in a JSON-formatted request body, like this:
{
"To": "+19995551234",
"From": "+12345556789"
}
To be perfectly honest, I don't know what the widget means by "Http Parameters". This could be HTTP Headers, URI parameters, or something else. I think the JSON form is clearer.
I came across the same situation. The solution for authentication is to change the url to include AccountSid and AuthToken
https://[AccountSid]:[AuthToken]#studio.twilio.com/v2/Flows/[SID]/Executions
Instead of Application / Json, use Form Parameters. Then add individual parameters below, for To, From, and Parameters​ (JSON string) for other variables.

Bitbucket API OAuth not redirecting properly

I'm trying to set up Bitbucket OAuth for my site but for some reason Bitbucket is not properly redirecting back to my site. I've created an OAuth key and secret and I'm using the Guzzle OAuth plugin in my Silex application.
First I request a temporary token via the oauth/request_token endpoint. Using that token I redirect to oauth/authenticate endpoint:
$app->get(
'/auth/bitbucket',
function () use ($app) {
$client = new Client('https://bitbucket.org/api/1.0');
$oauth = new OauthPlugin(
array(
'consumer_key' => $app['bitbucket.key'],
'consumer_secret' => $app['bitbucket.secret'],
'signature_method' => 'HMAC-SHA1',
'callback' => urlencode('http://mysite.local/auth/bitbucket/callback')
)
);
$client->addSubscriber($oauth);
$response = $client->post('oauth/request_token')->send();
parse_str($response->getBody(), $result);
return $app->redirect(sprintf('https://bitbucket.org/api/1.0/oauth/authenticate?oauth_token=%s', $result['oauth_token']));
}
);
This will bring up the page on the Bitbucket site where the user can grant or deny access to their account. After I click "Grant access" Bitbucket should redirect back to the callback url that was specified earlier but instead it will append my callback url to the Bitbucket url like this:
https://bitbucket.org/api/1.0/oauth/http%3A%2F%2Fmysite.local%2Fauth%2Fbitbucket%2Fcallback?oauth_verifier=xxxxxxxxxx&oauth_token=xxxxxxxxxxxxxxxxxx
This obviously results in a Bitbucket 404 page. Does anyone have an idea why the redirect to my callback url is not working properly?
According to documentation, when requesting token from bitbucket's API, you MUST have those parameters when sending POST request to https://bitbucket.org/api/1.0/oauth/request_token:
oauth_consumer_key
oauth_nonce
oauth_signature
oauth_signature_method
oauth_timestamp
oauth_callback
Also, don't urlencode your callback URL. Replace this:
'callback' => urlencode('http://mysite.local/auth/bitbucket/callback')
With this:
'callback' => 'http://mysite.local/auth/bitbucket/callback'
When you are sending POST request, you do not need to encode any of parameters.
Indeed, as you mentioned in comment, documentation does show encoded parameters in example, as in:
https://bitbucket.org/api/1.0/oauth/request_token?oauth_version=1.0&oauth_nonce=7f2325b3c36bd49afa0a33044d7c6930&oauth_timestamp=1366243208&oauth_consumer_key=HUpRcDUduZrepL6sYJ&oauth_callback=http%3A%2F%2Flocal%3Fdump&oauth_signature_method=HMAC-SHA1&oauth_signature=qZyTwVA48RzmtCHvN9mYWmlmSVU%3D
Issue you have is not wrong documentation, but misunderstanding of POST method. Also check Wikipedia page. Unlike GET where parameters are passed in URL, POST request method stores it's data in body. That allows us to send any data type, arbitrarily long.
Data that is passed in body of request is automatically encoded as in this example (copied from Wikipedia page):
Name=Jonathan+Doe&Age=23&Formula=a+%2B+b+%3D%3D+13%25%21
Looks similar to GET method when you encode data manually, right? However, if you urlencode data in POST request you actually end up with double encoded data, which is cause of problems in your case.
I really think that some basic knowledge of HTTP methods and Internet protocols is required before playing with any API.
Also, check some HTTP traffic monitor (debugger), like free Fiddler. It will allow you to see all HTTP data that is sent from your browser, essentially enabling you to learn by own examples.
I'm not sure how your framework works, but the callback parameter may be url encoded by the framework before the request is made. Since you also url encode it, your url is url encoded twice. Bitbucket will decode it once, leaving it with a url encoded url, which won't have the scheme set (http in this case), and your browser won't know it is an absolute URL, and will thus navigate to somewhere inside Bitbucket (as you observe). Try removing the extra url encode and see if that helps.

Get current fragment in Route, ASP.net MVC

Is there away to get the current fragment from a route that was issued via action link. This is how I am getting the action from the route.
string currentAction = requestContext.RouteData.Values["action"] as string ?? "index";
Can I do something similar to this?
string currentFragment = requestContext.RouteData.Values["Fragment"] as string ?? "";
No, you can't do anything like this. The fragment (everything that follows the # sign in an url) is never sent to the server by the browser, so the sole fact of talking about getting the url fragment server side simply doesn't make sense.
So if you have the following url: http://example.com/foo/bar?key1=value1#abc the server will never be able to fetch abc simply because the client will never send it.
As it has already been pointed out that is not possible. Document fragments (the string after the hash as you call it) are intended for the browsers only to correctly position the viewport. They have no meaning for the server and therefore are not transmitted there.
There is however a workaround you can use. Repeat the fragment as part of your url to make it accessible for the server.
Look at the permalink to the answers in this question. For instance, the link to my answer looks like this:
http://stackoverflow.com/questions
/6285833/get-current-fragment-in-route-asp-net-mvc/6286097#6286097
See how the value 6286097 is duplicated as the last route parameter. It's intentional. You can use this technique as well.
P.S. The fragment must point to an identifier in the document (id of some HTML element). At least in XHTML only identifiers work as fragments. Valid ids may not begin with a digit therefore instead of #6286097 use something like #answer-6286097.
P.S.#2. Do not use any JavaScript trickery to get around this limitation. Basic site functionality and design must work without JavaScript - don't listen to anyone who tells you otherwise. Fragments obviously belong to the basic tool box. Use JavaScript only for advanced interactivity.
I have a workaround for you, but first of all lets get more into the problem.
The strings after the hash symbol which are called Fragment values are not query parameters but they are strings to be read by the client-side (living in the browser) and the server cannot read them because they are not sent to the server by the browser.
Some authentication providers like Google and Azure send the access token as Fragment value for security reasons so that they are not transferred over the internet after they get sent as direct response from the authentication provider.
The only way you can come around that is to use javascript to convert the fragment values to query parameters by replacing the '#' with '?' and redirecting to the endpoint in your server controller.
I suppose the easiest way is to handle all that from server, meaning you get get the request in server, send a javascript code to the browser on the fly, that replaces the '#' into '?' and redirects to your second endpoint which reads the token as strong parameter.
Here how you can do it in ASP.NET Core 3.1:
[AllowAnonymous]
[HttpGet("authredirect")]
[Produces("text/html")]
public virtual ContentResult ConvertUrlFragmentToQueryParamThenRedirect()
{
return Content("<html><script>window.location.href=window.location.href.replace('#', '?').replace('authredirect', 'authparams')</script></html>", "text/html");
}
[AllowAnonymous]
[HttpGet("authparams")]
public virtual void GetAccessToken([FromQuery] string access_token)
{
// now you have your access token server side here
}
Please remember to set your redirectUrl to the correct one, in this case 'YOUR REDIRECT URL/authredirect'.

Twitter oauth_callback parameter being ignored!

I'm trying to get Twitter authentication working on my ASP.NET site. When you create the app on the Twitter website, you have to specify a callback URL, which for sake of argument, I have set to http://mydomain.com
I've read the oAuth 1.0a spec, and to override this callback URL with your own custom one you have to send the oauth_callback parameter in the request_token phase (url-encoded of course).
So my request URL looks like this:
http://twitter.com/oauth/request_token?oauth_callback=http%3A%2F%2Fmydomain.com%2Ftwittercallback
Supposedly, if all goes to plan, in your response data, you are supposed to receive a new parameter of oauth_callback_confirmed=true in addition to your token and token secret parameters.
However, my response comes through as:
oauth_token=MYTOKEN&oauth_token_secret=MYTOKENSECRET
I know I haven't given you guys the greatest amount to go on, but I'm at my wits end as to why I am not receiving the oauth_callback_confirmed parameter. Without this, my application keeps defaulting back to the callback URL hard-coded on the Twitter website. Please if anyone could help me out, I will be eternally grateful!
Thanks,
A.
I've read the oAuth 1.0a spec, and to
override this callback URL with your
own custom one you have to send the
oauth_callback parameter in the
request_token phase (url-encoded of
course).
So my request URL looks like this:
http://twitter.com/oauth/request_token?oauth_callback=http%3A%2F%2Fmydomain.com%2Ftwittercallback
just because YOU read the spec doesn't mean that TWITTER read it. :P
kidding - this is essentially correct - but the way twitter likes to receive this data is a little different (and not well documented).
the way i've found to get the oauth_callback to confirm is as follows: specify the oauth_callback in the parameters of the request function, NOT within the URL.
python example (using oauth2):
''' Create our client.'''
client = oauth.Client(consumer)
''' do the request '''
resp, content = client.request(request_token_url,"POST",body=urllib.urlencode({'oauth_callback':callbackURL}))
''' note that it's called "body" in this particular OAuth function for Client but in OAuth Request object it's called "parameters." YMMV depending on programming language/ library of course. '''
this is ALSO the only way i've managed to get an oauth verifier back. supposedly one should not have to specify the callback URL every time, since we provide it in app settings...but experience seems to indicate otherwise.
finally, please be aware that at leg 3 you have to do the same thing AGAIN - this time including the oauth_verifier as well as the callback URL in the parameters.
hope this helps - can't begin to tell you how much effort i put into figuring this out.
good luck!
J
I've used this guide to set up my PC to be used as the callback location. Basically you set up your hosts file in a certain way, clear your cache and add a couple of Firefox registry values. At the end when you are debugging an oauth call the redirect comes back to your local PC.
As I said it worked for me.
<?php
// oauth-php example
$token = OAuthRequester::requestRequestToken(
$consumer_key,
$user_id,
array('oauth_callback'=> urlencode($callback_uri))
);
?>

Resources