met4citizen / TalkingHead

Talking Head (3D): A JavaScript class for real-time lip-sync using Ready Player Me full-body 3D avatars.
MIT License
349 stars 107 forks source link

Request for CGI/Appendix B pipeline example #74

Open Dunya-8a opened 1 day ago

Dunya-8a commented 1 day ago

Hey @met4citizen! I really appreciate your work on this lovely project.

I've been trying to follow your steps in Appendix B, but I've never set up a CGI script and I am confused from the documentation about what I need to do. Can you share your test script as a template? It would also help a lot if you could describe more how to set things up, e.g. with the Apache server (which I have also never set up). My lack of experience here has been a huge bottleneck for several days and these would be such a time-saver!

met4citizen commented 1 day ago

Hi, and thank you.

First, I should point out that you don't need to setup JWT/SSO to use the TalkingHead class in your app. However, your app will likely need API keys, and it is never a good idea to include them in client-side code. Especially if you plan on sharing your app with others.

Another point is that you don't have to use an Apache web server. If you're more familiar with another web server that can act as an API proxy, that will work just as well. I'm not an expert in configuring web servers, but if you need help setting up a basic HTTPS server, there are plenty of online guides.

I won't include my actual CGI scripts here due to security and privacy concerns, but I can provide simplified examples for reference. In my own test app setup, I use shell scripts and the jwt-cli tool to generate and validate JSON Web Tokens. There are, however, many different JWT tools and libraries available for various programming languages (e.g., PHP, Python), see https://jwt.io/libraries.

Below is a simple example of a CGI shell script, get.sh, which generates a JSON Web Token. The needed Apache configuration can be found in the appendix. In this setup, the Apache server sets the remote user login name, which is included in the token. The referenced file,jwtsecretcontains the secret string used to sign the token. The token is set to expire in 10 minutes.

#!/bin/zsh

JWT=$(/opt/homebrew/bin/jwt encode --sub=$REMOTE_USER --exp='+10 minutes' --secret=@/opt/homebrew/etc/httpd/jwtsecret '{}')

if [ $? -eq 0 ]; then
  echo "Content-type: application/json"
  echo ""
  echo "{ \"jwt\": \"$JWT\" }"
else
  echo "Content-type: application/json"
  echo ""
  echo "{ \"error\": \"Internal error.\" }"
fi

Here is an example of what is returned to the calling app (this is not a real token):

{ "jwt": "eyIhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" }

When the three-part Base64-URL encoded string is included in an API proxy request, the web server invokes an external rewriting program to verify it. If the token is valid and has not expired, the program returns "OK", and the server permits the proxy pass. Below is a simplified example of an external rewriting program shell script, jwtverify.sh. Refer to the appendix for the relevant Apache configuration.

#!/bin/zsh

while read X
do
  XB=$(expr "$X" : "Bearer \(.*\)" "|" "$X")
  JWT=$(/opt/homebrew/bin/jwt decode --secret=@/opt/homebrew/etc/httpd/jwtsecret "$XB")
  if [ $? -eq 0 ]; then
    echo "OK"
  else
    echo "NOK"
  fi
done

This is just one way to approach it, and I'm sure it's not the most sophisticated method. Overall, setting up API proxies is beyond the scope of this project, but I hope this helps.