javascriptfacebook-graph-apicryptographynestjsinstagram-graph-api

Instagram API with Instagram Login Data deletion request URL route signed_request body data cannot validate


In my meta application with instagram api with instagram login when I define the "Data deletion request URL" the POST request send to my route with following body content

POST /api/delete HTTP/1.1
Host: 26d5-45-8-19-76.ngrok-free.app
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)
Content-Length: 166
Accept: */*
Accept-Encoding: deflate, gzip
Content-Type: application/x-www-form-urlencoded
X-Forwarded-For: 2a03:2880:30ff:8::
X-Forwarded-Host: 26d5-45-8-19-76.ngrok-free.app
X-Forwarded-Proto: https

signed_request=NybldKYslIBJJfCjH9jIE6PI3ohOKimGpB293v1ojeI.eyJ1c2VyX2lk.......

I can't verify the content using header provided based on the description that provided in following link Data Deletion Request Callback

I did following in the NestJS framwork service

import { Injectable } from '@nestjs/common';
import * as crypto from 'crypto';

@Injectable()
export class SignedRequestService {
  private readonly secret = 'appsecret'; // Use your app secret here

  parseSignedRequest(signedRequest: string): any | null {
    const [encodedSig, payload] = signedRequest.split('.', 2);

    // decode the data
    const sig = this.base64UrlDecode(encodedSig);
    const data = JSON.parse(this.base64UrlDecode(payload));

    // confirm the signature
    const expectedSig = crypto
      .createHmac('sha256', this.secret)
      .update(payload)
      .digest();

    if (Buffer.compare(Buffer.from(sig), expectedSig) !== 0) {
      console.error('Bad Signed JSON signature!');
      return null;
    }

    return data;
  }

  private base64UrlDecode(input: string): string {
    const base64 = input.replace(/-/g, '+').replace(/_/g, '/');
    return Buffer.from(base64, 'base64').toString('utf-8');
  }
}

Solution

  • I found what is the different between header and result and try to fix it, I don't know this is a correct way to verify the result or not but it seems working

    parseSignedRequest(signedRequest: string): {
      user_id: string;
      algorithm: 'HMAC-SHA256';
      issued_at: number;
    } {
      const [encodedSig, payload] = signedRequest.split('.', 2);
    
      // decode the data
      const data = JSON.parse(this.base64UrlDecode(payload));
    
      const secret = "app-secret";
    
      // confirm the signature
      const expectedSig = crypto
        .createHmac('sha256', secret)
        .update(payload)
        .digest('base64')
        .replace('=', '')
        .replace(/\+/g, '-')
        .replace(/\//g, '_');
    
      if (expectedSig !== encodedSig) {
        throw new BadRequestException('Bad Signed JSON signature!');
      }
    
      return data;
    }
    
    private base64UrlDecode(input: string): string {
      const base64 = input.replace(/-/g, '+').replace(/_/g, '/');
    
      return Buffer.from(base64, 'base64').toString('utf-8');
    }
    

    I will be happy to get any suggestions