A Very Helpful API – David Bushell – Freelance Web Design (UK)

By admin

Wednesday 13 Sept 2023
DATE


Two years ago
DATE

I built my own experimental media server + web app. It plays audiobooks and podcasts.

Earlier this year
DATE

I rewrote meSonic² from scratch. I corrected old bugs and design flaws in favour of new bugs and design flaws.

I rewrote the

SvelteKit
ORG

front-end. I coded an audio duration module to remove a big dependency on ffmpeg . I added proper SQLite integration. I also made heavy use of the Podcast Index API to avoid parsing XML feeds.

All in all v2 is a big improvement. There are issues I’ll correct in due course, but no showstoppers. That was until

last week
DATE

! Podcasts stopped syncing 😱

The Error

My app runs in a

Docker
PRODUCT

container. The log was flooding with this error:


02/09/2023
DATE


07:22:00
PERSON

Error:

401
CARDINAL

Unauthorized at fetchFromFresh (

file:///mesonic
NORP

/server/cache/

worker.ts:254:11
ORG

) at eventLoopTick (ext:core/01_core.js:183:11) at async

fetchAndCache
ORG

(

file:///mesonic
NORP

/server/cache/worker.ts:196:5)


401
CARDINAL

Unauthorized is the HTTP status returned from the Podcast Index API. The

API
ORG

is free to use but requires a key and authentication headers with each request.

I figured maybe my key had expired. Or maybe I’d been blocked for some reason. In testing my key was still valid. The documentation pages allow you to set a key and test endpoints — very cool. My API key worked just fine.

I edited my code to log the full response body. Adding more console logs is how debugging works, right?

Lo
PERSON

and behold the body had an detailed error explanation:

X-Auth-Date header value is not within the +/-

3 minute
TIME

time window. Please see: https://podcastindex-org.github.io/docs-api/#overview–authentication-details

Wow! Much appreciated!

The Fix

I had the error but I was confused as to why my implementation had stopped working.

The

API
ORG

requires

three
CARDINAL

auth headers:

X-Auth-Key — “Your API key string”

— “Your API key string”

X-Auth-Date
WORK_OF_ART

— “The current

UTC
ORG

unix epoch time as a string”

— “The current

UTC
ORG

unix epoch time as a string” Authorization — “A SHA-1 hash of the X-Auth-Key, the corresponding secret and the X-Auth-Date value concatenated as a string”

I guess the date is used this way so that API requests cannot be captured and replayed?

Anyway, since my code had been working unchanged for

months
DATE

, and my API key was still valid, the only explanation was that somehow it started using the wrong date.

Nothing wrong with my code:

const authKey = env . get ( ‘

PODCASTINDEX_APIKEY
ORG

‘ ) ; const authDate = Math . floor ( Date . now ( ) / 1000 ) . toString ( ) ; const authorization = await

sha1Hash
PERSON

( ` ${ authKey } ${ env . get ( ‘

PODCASTINDEX_SECRET
PERSON

‘ ) } ${ authDate } ` ) ; headers . set ( ‘x-auth-key’ , authKey ) ; headers . set ( ‘x-auth-date’ , authDate ) ; headers . set ( ‘authorization’ , authorization ) ;

Even I’m incapable of coding Date.now() wrong. I’ve made plently of bugs out of daylight savings before but now being

early September
DATE

this is unrelated.

The

Docker
ORG

container is running inside a Proxmox virtual machine.

I

SSH’d
DATE

into the VM and ran

timedatectl
ORG

:

Local time:

Tue 2023-09-02
DATE


10:05:59
TIME

BST Universal time:

Tue 2023-09-02
DATE

09:05:59 UTC

RTC
ORG

time:

Tue 2023-09-02
DATE

09:05:59 Time zone:

Europe
LOC

/

London
GPE

(BST, +0100) System clock synchronized: no NTP service: inactive

RTC
ORG

in local

TZ
ORG

: no

Sure enough the VM date & time was

five minutes
TIME

behind.

This was the source of my error. There was nothing to keep time synchronized. I’m guessing the server time slowly drifted as the VM was occasionally restarted. Whatever minimal Debian

12
CARDINAL

install I setup had no NTP service. Not something I even thought to consider. In the past I’ve used Ubuntu where “minimal” has a broader definition.

I fixed this with apt install chrony . I restarted the

Docker
ORG

container and the Podcast Index API was happy to accept my requests again!

The Thanks

Big thanks to the Podcast Index team for such a thoughtful

API
ORG

design and documentation.

I can’t imagine how long it would have taken me to find the root cause had it not been for the response body. With only a

401
CARDINAL

Unauthorized to go on I’d have wasted

hours
TIME

testing

API
ORG

credentials on my local machine and failed to replicate the bug.

Not even Docker was able to solve the “works on my machine” in this case. Docker in a VM is not as crazy as it sounds. I should blog on that in future.