Buy
Buy

How does authentication normally work on the web? Usually, after we send our username and password, a cookie is returned to us. Then, on every request after, we send that cookie back to the server: the cookie is delicious, and identifies who we are, it's our key to the app. The server eats that cookie, I mean reads that cookie, and looks it up in some database to figure out who we are.

How all (most) API Authentication Works

Guess what? An API isn't much different. One way or another, an API client will obtain a unique token, which - like the cookie - acts as their key to the API. On every request, the client will send this token and the server will use that token to figure out who the client is and what they're allowed to do.

How does it do that? Typically, the server will have a database of tokens. If I send the token I<3cookies, it can query to see if that's a valid token and to find out what information might be attached to it - like my user id, or even a list of permissions or scopes.

By the way, some of you might be wondering how OAuth fits into all of this. Well, OAuth is basically just a pattern for how your API client gets the token in the first place. And it's not the only method for obtaining tokens - we'll use a simpler method. If OAuth still befuddles you, watch our OAuth2 Tutorial. I'll mention OAuth a few more times, but mostly - stop thinking about it!

Anyways, that's token authentication in a nut shell: you pass around a secret token string instead of your username and password.

A Better way? JSON Web Tokens

But what if we could create a simpler system? What if the API client could simply send us their user ID - like 123 - on each request, instead of a token. Well, that would be awesome! Our application could just read that number, instead of needing to keep a big database of tokens and what they mean.

Alas, we can't do that. Because then anyone could send any user ID and easily authenticate as other users in the system. Right? Actually, no! We can do this.

In your browser, open jwt.io: the main website for JSON web tokens. These are the key to my dream. Basically, a JSON web token is nothing more than a big JSON string that contains whatever data you want to put into it - like a user's id or their favorite color. But then, the JSON is cryptographically signed and encoded to create a new string that doesn't look like JSON at all. This is what a JSON web token actually looks like.

But wait! JSON web tokens are encoded, but anyone can read them: they're easily decoded. This means their information is not private: you would never put something secret inside a JSON web token, like a credit card number - because - it turns out - anyone can read what's inside a JSON web token.

But here's the key: nobody can modify a JSON web token without us knowing. So if I give you a JSON web token that says your user ID is 123, someone else could steal this token and use it to authenticate as you. But, they cannot change the user ID to something else. If they do, we'll know the token has been tampered with.

That's it! JSON web tokens allow us to create tokens that actually contain information, instead of using random strings that require us to store and lookup the meaning of those strings on the server. It makes life simpler.

Oh, and by the way - once you eventually deploy your API, make sure it only works over SSL. No matter how you do authentication, tokens can be stolen. So, use HTTPS!

Now that we know why JSON web tokens - or JWT - rock my world, let's use them!

Leave a comment!

  • 2018-11-17 Coder

    Thats a long answer. I think I did not understand most of the things, I need to reread it slower but currently have other stuff to watch. I mark it to come back later. But one thing instatly raises question to me:

    "So, if api tokens did not exist, we would be forced to give other apps our password. And then, if we changed our password (because we wanted to deny access to 1 app that we shared it with), we would invalidate access for all of those apps."

    You mean 1 password for every user? I think every user would have their own pasword and so we just deny access to one user. But since I did not take time to think much, that might be a reason why I did not understand.

  • 2018-10-29 weaverryan

    Hey Coder !

    Really good question. The WHOLE point of "API tokens" is this: to have some "string" that allows access that is different than the user's password. Let me say it a different way. Yes, if you're using SSL, there is no security risk to sending your email/password, credit card information, API token or anything else to the server. So then, why do we have API tokens at all? Why not just have the user *always* send their email/password to the API endpoints?

    Actually, this *is* a valid way to do it. And, like we just talked about, over https, this doesn't really have any security implications.
    The *real* reason for API tokens is that you can create an API token and safely give it to someone else. Then, if you decide that this "other person/app" should not have access to your account anymore, you could (in theory, it depends on how you build your system) invalidate/delete that API token. Heck, you could give out 10 different API tokens to 10 different users. And if you want to deny access to just one of them, you only need to invalidate/delete that API token for 1 app. The other 9 will work, as will your password. Additionally, in a more complex system, you can make some tokens have different permissions than others.

    So, if api tokens did not exist, we would be forced to give other apps our password. And then, if we changed our password (because we wanted to deny access to 1 app that we shared it with), we would invalidate access for all of those apps. This is how, for example, OAuth works with Facebook. If you clicked "Login with Facebook" on SymfonyCasts, you are basically creating & giving SymfonyCasts an API token that gives some access to your Facebook account. SymfonyCasts then sends that token on API requests to Facebook to perform certain actions "as you" (well, we don't do that - we just fetch your email for login purposes, but you get the idea). If you wanted to "invalidate" our access, you could go to Facebook and "revoke our access", which basically makes our API token invalid.

    Phew! The big question with all this API token stuff is: how do you want your users to be able to create API tokens? In this simple app, we created an API endpoint where you can create them. Then, in theory, you could safely give those to someone else. We could also implement an OAuth server (then we would operate a big like Facebook) OR we could create a simple profile section where each user can manually create access tokens (you can do this on GitHub). We actually have an entire short video on this exact topic: https://symfonycasts.com/sc...

    Let me know if that helps!

    Cheers!

  • 2018-10-28 Coder

    I did not get. So the benefit is that we send user id, and we get jwon web token which contains various information? But we first maybe have to still send username and password, so that anyone would not be able to send the user id and get information about the user?

    If that is how I wrote then: why we cannot send credit card information if the user is authenticated and we send that token over SSL? Nobody besides authenticated user will be able to see the credit card information.

  • 2017-11-01 weaverryan

    Hey einue!

    Ah, very interesting question :). I'll explain a bit using the new (version 2) of the https://github.com/lexik/Le..... though the details will essentially be the same for version 1.4.

    The most important thing to know is that the bundle relies on a *different* library to actually do the key stuff. It either uses https://github.com/namshi/jose or https://github.com/lcobucci... based on your configuration. So let's talk about the first. If you look at their docs, they explain it fairly well: https://github.com/namshi/j.... Basically, the private key is used to sign the key, and then the public key is used to verify it.

    This *is* different than asymmetric key encryption. But... it's kind of the same idea in a different direction. I may be off on some finer details (security is always tricky), but basically, if you have a public and private key, you can use it in 2 different ways:

    A) Encryption: Encrypt data with a public key, and decrypt with a private key (like how SSL works)
    B) Signing: Sign data with a private key and "verify" its authenticity with a public key (JWT)

    I hope that helps!

    Cheers!

  • 2017-10-30 einue

    Can you point out, when the private key and when the public key is used? I think it is different from an asymmetric key encryption scheme?

  • 2016-10-16 weaverryan

    Just making sure you're aware ;). Thanks for pointing that out - we'll get that fixed and re-export.

    Cheers!

  • 2016-10-16 Johan

    The typo at 3:54 "authenticting" triggered me a bit, just a little bit though ;)