सभी लेख
embedded Tomcat पर Spring Boot RestController लोकल टनल से मिले raw byte[] payload से webhook सिग्नेचर header सत्यापित करता है।
Spring BootJavawebhook debugginglocal testing

Spring Boot वेबहुक: raw body, CSRF छूट और सिग्नेचर header

Spring Boot @RestController से webhook endpoint आसान बनाता है, पर Spring Security CSRF और JSON converter handler से पहले payload ब्लॉक या बदल सकते हैं। लोकल टेस्टिंग raw byte[] एक्सेस, webhook path पर CSRF छूट और untouched bytes पर सिग्नेचर सत्यापन साबित करे।

@RestController webhook endpoint बनाएँ

Webhook controller पतले रखें। Raw bytes लें, सिग्नेचर सत्यापित करें, फिर deserialize:

@RestController
@RequestMapping("/webhooks")
public class StripeWebhookController {

    @PostMapping("/stripe")
    public ResponseEntity handle(
            @RequestBody byte[] payload,
            @RequestHeader("Stripe-Signature") String signature) {

        if (!verifier.isValid(payload, signature)) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
        }
        JsonNode event = objectMapper.readTree(payload);
        handler.process(event);
        return ResponseEntity.ok().build();
    }
}

@RequestBody byte[] Tomcat द्वारा मिला सटीक payload रखता है — जब provider raw JSON साइन करता है तो आदर्श।

HttpServletRequest से raw body पढ़ें

वैकल्पिक: servlet request से सीधे पढ़ें:

byte[] body = request.getInputStream().readAllBytes();
String sig = request.getHeader("Stripe-Signature");

पहले POJO या Map bind न करें — Jackson reserialize HMAC तोड़ता है। सिग्नेचर सत्यापन गाइड देखें।

केवल webhook path पर CSRF बंद करें

Spring Security डिफ़ॉल्ट CSRF चालू करता है। server-to-server छूट के बिना webhook POST 403 देते हैं:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf(csrf -> csrf.ignoringRequestMatchers("/webhooks/**"));
        return http.build();
    }
}

ignore को /webhooks/** तक सीमित रखें — CSRF globally बंद न करें।

बिज़नेस लॉजिक से पहले सिग्नेचर header सत्यापित करें

Provider header पढ़ें, raw byte array से digest बनाएँ, constant-time compare करें। गलत पर 401, सफल पर तेज़ 200।

लोकल टनल workflow

  1. चलाएँ: ./mvnw spring-boot:run पोर्ट 8080।
  2. Tomcat expose: npx portpreview 8080
  3. टनल URL + path डैशबोर्ड में पेस्ट करें।
  4. टेस्ट इवेंट भेजें और logs देखें।
  5. Idempotency के लिए same event ID replay — retry पैटर्न

आम जाल

Filter क्रम और body consumption

Controller से पहले stream पढ़ने वाले filter खाली stream छोड़ते हैं। ज़रूरत हो तो ContentCachingRequestWrapper

Global @RequestBody binding

जल्दी JSON parse करने वाला @ControllerAdvice bytes बदल सकता है। Webhook byte[] से अलग रखें।

धीमे handler retry trigger करते हैं

जल्दी ACK, async process, event ID से dedupe।

और पढ़ें

मूल बातें पढ़ें localhost टनलिंग और लोकल webhook डिबगिंग. सिग्नेचर मैकेनिक्स के लिए देखें सिग्नेचर सत्यापन गाइड. डुप्लिकेट-सुरक्षित हैंडलर के लिए पढ़ें retry और idempotency पैटर्न. PortPreview मुफ़्त शुरू करें.

अक्सर पूछे जाने वाले प्रश्न

Spring Boot webhook 403 क्यों देता है?
Spring Security CSRF session token के बिना POST ब्लॉक करता है। webhook path के लिए csrf.ignoringRequestMatchers जोड़ें और सिग्नेचर सत्यापित करें।
webhook के लिए byte[] या POJO?
सिग्नेचर के लिए byte[] इस्तेमाल करें। POJO binding JSON reserialize कर HMAC तोड़ता है।
Spring Boot webhook को लोकल कैसे टेस्ट करें?
8080 पर spring-boot:run चलाएँ, npx portpreview से expose करें, टनल URL पेस्ट करें और टेस्ट इवेंट भेजें।