APIs & Integrations

du-it
Participant

How to reach the webhook application defined in the redirect-url?

I have managed it so far to create an app in my developer account and connected it to the HubSpot CRM. I created the token by entering

 

https://app.hubspot.com/oauth/authorize?client_id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx&redirect_uri=...

 

in a web browser and used the code parameter obtained with the response in

 

https://api.hubapi.com/oauth/v1/token?grant_type=authorization_code&client_id=xxxxxxxx-xxxx-xxxx-xxx...

 

by using Postman. For anybody who uses this as an guide to do: Ensure to submit x-www-form-urlencoded!!! Otherwise the request will fail!

 

Because HubSpot does solely make HTTPS requests to the webhook I set up a minimalistic Spring Boot 2 application configured to use HTTPS (what obviously works because the first mentioned call succeeded).

 

Here's the minimalistic controller:

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value="/", produces=MediaType.APPLICATION_JSON_VALUE)
public class HubSpotServiceController {

    @GetMapping("/hubspot")
    public String healthcheck() {
        return "Service is available.";
    }
    @PostMapping("/hubspot")
    public String hubSpotChange(final @RequestBody String hsObject, final HttpServletRequest request) {
        System.out.println (String.format("A HubSpot notification was received from %s!", request.getRemoteAddr()));
        System.out.println (om.writerWithDefaultPrettyPrinter().writeValueAsString(hsObject));
        return om.writerWithDefaultPrettyPrinter().writeValueAsString(String.formatA HubSpot notification was received from %s!\n", request.getRemoteAddr(), om.writerWithDefaultPrettyPrinter().writeValueAsString(hsObject)));
    }
}

I created a certificate using:

keytool -genkeypair -alias hubspot -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore duit.p12 -validity 3650

and stored it under

src/main/resources/keystore .

In application.properties I specified:

server.port=${APPLICATION_PORT:8888}
# The format used for the keystore.
server.ssl.key-store-type=PKCS12
# The path to the keystore containing the certificate
server.ssl.key-store=classpath:keystore/duit.p12
# The password used to generate the certificate
server.ssl.key-store-password=hubspot
# The alias mapped to the certificate
server.ssl.key-alias=hubspot

When I enter the URL in a browser I get a security warning but I can continue and my endpoint is entered.

What I want is that property changes in HubSpot shall be propagated to my Spring Boot app (the webhook) but in HubSpots monitoring tool I can see:

 

"Webhook attempt failed due to a refused connection."

 

...and my endpoint is NOT entered.

 

I played around with ServiceConfig but I get a 403 when entering the URL in the web browser. Here's the ServiceConfig class:

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
//@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    protected void configure(final HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable();
//        http.authorizeRequests().anyRequest().fullyAuthenticated();
        http.antMatcher("/**")
                .authorizeRequests()
                .antMatchers("/").permitAll()
                .anyRequest().authenticated()
//                .and().oauth2Login();
//                .and().formLogin();
        ;
    }
}

Of course, I don't want to have a form login. HubSpot shall be trusted to invoke the service's endpoint.

 

What do I have to do? How can HubSpot authenticate when invoking the webhook (the Spring Boot app)? ...and ONLY HubSpot may be authorized to call this endpoint!

0 Votes
9 Réponses
IsaacTakushi
HubSpot Employee
HubSpot Employee

How to reach the webhook application defined in the redirect-url?

Hi, @du-it.

 

Thanks for the detailed post.

 

When I've seen "Connection refused" errors in the past, it's been due to either self-signed certificates, unrecognized certificate authorities, or incomplete certificate chains.

 

That said, I looked into your app (ID ending in 1635) and tested one of your webhook subscriptions and received a REQUEST_TIMED_OUT error instead, per the screenshot below:

 

REQUEST_TIMED_OUT.jpg

When I enter your URL in my brower, I also (eventually) receive a "took too long to respond error."

Isaac Takushi

Associate Certification Manager
0 Votes
du-it
Participant

How to reach the webhook application defined in the redirect-url?

Well, the time out surely comes because the defined redirect-url points to a dynDNS which I configured in my router. This, in turn, redirects to the service endpoint on my local machine ...when it's runing. 😉

Recently the service was only available when my IDE is running. I'll let the WAR run from now on so that it shold be available at least when my machine is online.

I added some new information to my question (ServiceConfig).

0 Votes
IsaacTakushi
HubSpot Employee
HubSpot Employee

How to reach the webhook application defined in the redirect-url?

Hi, @du-it.

 

Apologies for the delayed response. Thanks for clarifying.

 

Would it be possible to enter your service endpoint directly into the Target URL field in your app's webhook settings (instead of your redirect_uri)? I tried testing the webhook subscription a couple times yesterday but still received REQUEST_TIMED_OUT errors. Perhaps your machine wasn't online at those times.

Isaac Takushi

Associate Certification Manager
0 Votes
du-it
Participant

How to reach the webhook application defined in the redirect-url?

I'm sorry. Yes, my machine was down. I'll let it up the hole day today. 😉

I already entered the endpoint in the target URL field.

0 Votes
IsaacTakushi
HubSpot Employee
HubSpot Employee

How to reach the webhook application defined in the redirect-url?

Hey, @du-it.

 

Are you online right now? I just sent a test and received another REQUEST_TIMED_OUT error. I'm in EST (GMT-5) and will be online until roughly 16:30 EST.

Isaac Takushi

Associate Certification Manager
0 Votes
du-it
Participant

How to reach the webhook application defined in the redirect-url?

When I enter https://duit.ddnss.ch:8888/hubspot in a browser I get a repsonse. I'm in UTC+1

0 Votes
IsaacTakushi
HubSpot Employee
HubSpot Employee

How to reach the webhook application defined in the redirect-url?

Sorry, @du-it, I'm not able to reach it on any browser.

 

Screen Shot 2020-02-06 at 7.10.59 AM.png

Isaac Takushi

Associate Certification Manager
0 Votes
du-it
Participant

How to reach the webhook application defined in the redirect-url?

I have set up a second service now which are both running right now:

 

1. https://duit.ddnss.ch:8887/hubspot 

is the webhook to the service which requires authentication (defined in SecurityConfig.class)

2. https://duit.ddnss.ch:8888/hubspot 

is the webhook to the service which permits all (defined in SecurityConfig.class)

(Requires a JSON in the request body.)

 

I have set up a second app in my developer account as well and connected it to the CRM.

 

Invoking the first URL in a browser I get:

 

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Thu Feb 06 19:42:16 CET 2020
There was an unexpected error (type=Forbidden, status=403).
Access Denied
 
Invoking the second URL in a browser I get:
 
"Service is available for call from 84.175.83.116!"
 
Using Postman to test the POST endpoint (consider the JSON in the request body):
1. on port 8887:
{
    "timestamp""2020-02-06T18:59:17.861+0000",
    "status"403,
    "error""Forbidden",
    "message""Access Denied",
    "path""/hubspot"
}
 
2. on port 8888:
"A HubSpot notification was received from 84.175.83.116!"
 
But changing some contact data in HubSpot the webhook notification is monitored but it failed for both apps (at port 8887 and 8888) due to:
 
Webhook attempt failed due to a refused connection.
 
I think this is becaue of the selfsigned certificate but I am wondering why HubSpot monitors in both cases (even on port 8888 with 'permitAll') that there is a refused connection.
 

I just found https://developers.hubspot.com/docs/faq/v1-request-validation.

Is the usage of a certificate not possible with HubSpot webhooks because they send X-HubSpot-Signature? Is it that I have to grant permission to the endpoint and verify the signature inside? This means that I can't use the authenticate() method in SecurityConfig? ...and do I always have to enter the endpont and validate against the request signature?

0 Votes
IsaacTakushi
HubSpot Employee
HubSpot Employee

How to reach the webhook application defined in the redirect-url?

Hi, @du-it.

 

Apologies for the delayed response; I have been out of the office.

 

Thank you for sharing all of this information. I now receive CONNECTION_REFUSED errors when I send test webhook notifications within your app ending in 1635.

 

I too believe the issue stems from your self-signed certificate.

 

I most commonly see the webhooks app throw CONNECTION_REFUSED errors when the root certificate authority returned cannot be found in HubSpot's Java TrustStore.

 

A few customers in the past have opted for Let's Encrypt or more common public CAs, as you probably saw in this related Community thread.

 

I'm not sure I follow you when you say "I am wondering why HubSpot monitors in both cases (even on port 8888 with permitAll) that there is a refused connection." HubSpot is not completing the TLS handshake because it does not trust your self-signed certificate. Have I misunderstood your question?

 

Certificates can be used in conjunction with the X-HubSpot-Signature header. HubSpot does not require that you authenticate it — the header value just allows you to set up authentication on incoming POST requests if you wish. You can ignore the signature values for now since they aren't affecting the TLS handshake.

Isaac Takushi

Associate Certification Manager
0 Votes