Session IDs are bound to cookies from a given origin. Thus, every request needs to include the original cookie, and have the same origin, to transport authentication data. But cookies cannot be accessed from JavaScript, only be sent implicitly if these things are true.
This made it difficult to work with separate hosts (www.my.app vs. api.my.app).
In contrast, Bearer tokens are explicit: JavaScript code can use and attach them to requests as appropriate, thus allowing for more control. The also are a little easier to work with (no reason to keep a cookie jar, stateless stuff works).
JWTs in turn aren't simply random strings anymore -- they contain some claims about the bearer, which are cryptographically signed, so whoever receives the token can be sure the claims haven't been tampered with. This allows for very powerful, interconnected services -- but most people use them to pass a session ID around, so... here we are :)