invalid_client for code validation on server

I'm trying to validate the code on a cloud function but I always get same result "invalid_client". Bellow you have my NodeJs function with an example key:


import * as functions from 'firebase-functions';
import * as rp from "request-promise-native";
import * as buildURL from "build-url";
import * as jwt from "jsonwebtoken";

const privateKey = '-----BEGIN PRIVATE KEY-----\n' +
  'MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgP8TqTrmSMJeaBZv+\n' +
  'eOHFL8Y4b1jTIrb8d7FVIFR7vVOgCgYIKoZIzj0DAQehRANCAAQSqhtbJHJ0J24T\n' +
  'vAxnANEY7m1yZJ/J7VTGXHGXWic/8xgvOIkhGnmdwgD/oCmIvjo/6yL1hlEx51hr\n' +
  'EGErDIg1\n' +
  '-----END PRIVATE KEY-----';

const home = 'eu.long1.signinwithappleexample://eu.long1.signinwithappleexample/auth';
const clientId = 'eu.long1.signinwithappleexample.android';
const keyId = 'TB943KQS2Y';
const teamId = 'DKY2FBVP6L';
const audience = 'https://appleid.apple.com';
const tokenEndpoint = 'https://appleid.apple.com/auth/token';

export const callback = functions.https.onRequest(async (request, response) => {
  const data = <AuthResponse>request.body;
  let params: { [key: string]: string } = {state: data.state};
  if (data.error) {
  response.redirect(buildURL(home, {queryParams: {...params, error: data.error}}));
  } else if (!data.code) {
  response.redirect(buildURL(home, {queryParams: {...params, error: 'no_code'}}));
  } else {
  try {
  const jwtOptions = {
  keyid: keyId,
  algorithm: 'ES256',
  issuer: teamId,
  audience: audience,
  subject: clientId,
  expiresIn: 60
  };
  const clientSecret = jwt.sign({}, privateKey, jwtOptions);
  const result = await rp.post(tokenEndpoint, {
  headers: {'Content-Type': 'application/x-www-form-urlencoded'},
  formData: {
  client_id: clientId,
  client_secret: clientSecret,
  code: data.code,
  grant_type: 'authorization_code',
  redirect_uri: 'https://us-central1-flutter-sdk.cloudfunctions.net/callback'
  }
  });
  response.redirect(buildURL(home, {queryParams: {...params, result: result.body}}));
  } catch (e) {
  response.redirect(buildURL(home, {queryParams: {...params, error: e.error}}));
  }
  }
});

interface AuthResponse {
  readonly code: string | undefined
  readonly id_token: string | undefined
  readonly state: string
  readonly user: AuthResponseUser | undefined
  readonly error: string | undefined
}

interface AuthResponseUser {
  readonly name: AuthResponseUserName | undefined
  readonly email: string | undefined
}

interface AuthResponseUserName {
  readonly firstName: string | undefined
  readonly lastName: string | undefined
}


My idea is that the signing of the client_secret is wrong for some reason. Any help?

Replies

What I can briefly note is that you are missing User-Agent header which is required by Apple.