Authentication: who are you? Proofs are passwords, codes and keys

2025-12-14

Identity - who are you?

In many systems, various actions can only be performed as some kind of Identity. We must authenticate ourselves by proving who we are. Authentication fundamentally is just an answer to this question: who are you and can you prove it is true?

Authentication is all about Identity, it does not protect from unauthorized access to specific resources and actions on them. That is what Authorization is responsible for (link to future post will follow). The main goal of authentication is to identify the entity that wants to use our system, making sure that it is authentic as well. We are then able to associate all actions performed in the system with identities - it allows a few useful things:

That is what authentication is on a high level; a fundamental concept of proving one's identity without which many systems and functionalities simply could not be built. There is a multitude of possible implementations, but fundamentally they are very similar and lead to the same place. Let's now explore them and see - why it is the case and how it works exactly.

Passwords

The simplest, first and still widely used authentication method. There is a username:password pair that proves we are the claimed username. To support it in service A, there must be a process of:

From that point onward, there is no need to present a username:password pair with each action/request we make; that would be not only unsecure, requiring to input a password repeatedly everywhere, but also annoying and slow - passwords are stored and compared as hashes, created with deliberately slow hash functions. Instead, after providing the correct username:password combination, we are given something in return; something that basically is an equivalent, a substitute of expected username:password value. What is it?

Temporary Identity Proofs: sessions and tokens

In exchange for providing the correct username:password pair, we get:

Temporary Identity Proof - stateful session or stateless token.

It essentially is a proof of proof - information stating that we have successfully gone through the authentication process, of any complexity and number of steps, and we have proven our Identity.

Passwords are just one instance of many possible authentication methods - as we are about to see, the underlying mechanism works more or less the same for all cases:

But, why do we even need it? What are the benefits of having this additional indirection layer?


How different are sessions and tokens in this context?

Sessions are stateful - after successful authentication:

Tokens are stateless (mostly) - after successful authentication:

In summary, sessions and tokens work in a slightly different fashion, but the end result is the same: after successfully going through an authentication process, which proves the identity, we receive a session or token that is then used on each action/request as a Temporary Identity Proof - making the process faster, simpler, more flexible and secure.

Let's now get back to other than username:password authentication methods - there are a couple of them and each comes with different mechanics and tradeoffs.

Enjoying this piece? Get the Binary Log Newsletter - deep and broad dives, discoveries and distilled insights for driven developers who care about the craft:
No spam, no fluff - pure signal. Unsubscribe anytime.

Codes

These are various techniques that generate random and time-limited codes of different lengths - usually numeric or alfanumeric. They are often used as a second factor in Multi-Factor Authentication (MFA) setups, but not only - another popular application are Magic Links. How does it work there?

To our identity (account), an email or phone number is linked (or any other external messaging platform) - no need for a password. Then, signing in:

  1. we enter an email or phone number
  2. server checks whether associated identity exists; if it does:
    1. short-lived (few minutes) code is generated
    2. it is saved in the server's database
    3. magic link is constructed - it contains the code & email/phone number/username and redirects to a sign-in page; something like: https://the-best-app.com/sign-in?email=<email>&code=<code>
    4. it is sent to the client (us)
  3. we receive the magic link
  4. we click on it and are redirected to the sign-in page
  5. on the sign in page, email and code are extracted from query params and sent to the server
  6. if valid, the server returns a Temporary Identity Proof: session or token
  7. we are authenticated and prove it on each action/request by presenting the received session or token

With magic links, there is no need to store and use passwords, which is very convenient - for both servers and users. The solution as a whole is as secure as the access to the messaging platform (email, phone number, application) is - if somebody hacks it, they are able to take control over our account (identity). Fortunately, generated codes are short-lived; if they get stolen, most likely they will already expire and no longer be valid for an attack to take place.

In the two and multi factor authentication setups, codes are used in a likewise fashion. The key difference is that they are generated and sent only after one or few other authentication factors are presented - more on this below.

Factors: Single vs Multi

In the authentication processes described so far - passwords and codes (magic links) - there was only a single factor (proof). We were supplying a password or temporary code sent to the messaging platform controlled by us: are there any issues with this approach?

Well, there is only one factor, a single proof of an identity. If this factor gets stolen, the thief can impersonate us and take control over the identity.

With Two-Factor Authentication (2FA), even if one authentication factor gets stolen, password for example, an attacker still cannot control our identity, since two factors must be presented in the right order to prove identity - it is much more secure. The authentication process itself is similar to what we already know:

There are many various second factor methods available. Some of the most popular ones include:


With two or more authentication factors we have increased security, but a new problem arises:

What if control over the second factor is lost? Without it, access to the identity is not possible - how to restore it?

In Single-Factor Authentication (SFA) this problem does not exist - there is only one factor that represents control over identity and in most cases passwords are used; I forgot my password procedure allows to reset them through a special link, sent by email. With Two-Factor Authentication (2FA), if the second factor is lost, most platforms support the following recovery methods:

As we can see, there is much more complexity involved in supporting two (multi) factor authentication as compared to just a single one. There also is an additional learning curve for users, but the security benefits are in most cases more than worth it.

In conclusion, Multi-Factor Authentication (MFA) requires providing multiple proofs of our identity (most commonly two), but in the end it works as the simplest, single factor process does: we go through the multi-step authentication process and get a session or token (temporary identity proof) linked to the proven identity in exchange. It once again shows the benefits of separating the process from issuing a proof of its success - it is extremely flexible, details of this procedure may be changed at any time, but temporary identity proofs - sessions and tokens - remain the same.

Keys

This is a slightly different approach, used mainly for machine-to-machine (M2M) authentication. Primarily, it can be found in:

In the SSH protocol, we exchange data between two machines - client and server. Both of them use public key cryptography to generate two mathematically related keys: public and private. A public key serves as identity here; control over related private key proofs it. If a private key gets stolen, the identity associated with its public key is lost as well. The server accepts connections only from clients identified by a preconfigured list of public keys, generally described in the .ssh/authorized_keys file. Then, after agreeing on the details like supported protocol versions and cryptographic algorithms, both server and client authenticate each other:

If the exchange is successful, both client and server know they are talking with a genuine party. Being connected, they generate a random, shared secret; used only by the current connection and its session. This ephemeral secret serves both as Temporary Identity Proof as well as symmetric key to encrypt and decrypt exchanged over the network data.

In Mutual TLS (mTLS), both client and server authenticate each other. In classic TLS (used in HTTPS), only the server has a certificate that proves its identity by being related to a trustworthy public/private key pair - the certificate is commonly signed by a certificate authority (CA) or sometimes is self-signed. For mutual authentication:

If the exchange is successful, both client and server know they are talking with a genuine party. Then, exactly as in the SSH protocol, a random, shared secret is generated and used only by the current connection and its session. This ephemeral secret likewise serves both as Temporary Identity Proof as well as symmetric key to encrypt and decrypt exchanged over the network data.

In both cases, no passwords or other factors are involved - only public/private key pairs and a way to distribute and link them to identities. Because of the latter, for more complex systems and use cases, we might need to set up PKI - Public Key Infrastructure. But for simpler ones, like a few machines exchanging data through SSH or mTLS between services running in an internal network, usually a script or scripts will do the job. After mutual server-client authentication, a random and shared ephemeral secret serves as Temporary Identity Proof, scoped to a single connection and its current session.

API Tokens/Keys

Another approach mainly for machine-to-machine (M2M) authentication (and authorization, outside the scope of this post) - mostly used by various REST APIs to validate authenticity of the clients and their access rights. Sometimes called API Tokens, sometimes API Keys; it is the same thing.

Here, Temporary Identity Proofs are not involved. We simply generate static API Token/Key on the target platform - GitHub, DigitalOcean, OpenAI, Buttondown etc. It is a random, long string that is linked to our account and can be further identified by custom name or id and given a set of permissions to restrict what is allowed to do (authorization that is). Most often, it expires after a certain time for security reasons - 7 days, 30 days, 90 days and so on. It might be regenerated or revoked at any time, since it is centrally controlled through the platform we are integrating with. These tokens/keys are added to each HTTP (or other) request - usually as the Authorization header or sometimes a query parameter. Because they are static, included in each action/request and rather long-lived - making sure they are used in a secure context is crucial. If somebody steals this token/key, they can impersonate us and start using the given API at our cost.

Delegated Authentication

Lastly, service A may delegate authentication to service B, putting trust in its process. The best example of this approach is Sign In with X feature: allowing signing in to a website/app using an existing account (identity) from Google, Apple, LinkedIn, Twitter/X, Facebook, GitHub, etc.

In this context, OpenID Connect (OIDC) standard/protocol is often taken advantage of, but the principle is more universal:

Now, service A can either use tokens/sessions issued by service B or generate their own, based on the data received from service B. In either case, after a successful and fully delegated authentication process, Temporary Identity Proofs as tokens or sessions are used again.

Closing thoughts

We went through pretty much all possible ways of resolving the authentication question: who are you and can you prove it is true? The question both humans and machines must repeatedly answer.

We saw that there are many different authentication methods based on which we might build every imaginable authentication process - from simple to complex, requiring single or multiple authentication factors.

Excluding static API Tokens/Keys, a common pattern arises:

Which allows to decouple authentication process details and all its complexity from the result - failure or proven identity. Other benefits include improved performance, simplicity, more security and flexibility.

Let's then close by answering the authentication question - we prove who we are by providing various factors: passwords, codes and keys; one, two and sometimes more even. In exchange, a session, token or ephemeral secret is created and sent; it serves as a more flexible and temporary proof of our identity, for every action/request we make.

Like this type of content? Get the Binary Log Newsletter - deep and broad dives, discoveries and distilled insights for driven developers who care about the craft:
No spam, no fluff - pure signal. Unsubscribe anytime.

Notes and resources

  1. Various kinds of Identity
  2. Basic Authentication - passwords in the HTTP protocol: https://en.wikipedia.org/wiki/Basic_access_authentication
  3. Cryptographic hashes and why passwords ought to be stored as hashes produced by deliberately slow hash functions: https://en.wikipedia.org/wiki/Cryptographic_hash_function
  4. Sessions in general: https://en.wikipedia.org/wiki/Session_(computer_science)
  5. JSON Web Tokens (JWTs):
    1. https://en.wikipedia.org/wiki/JSON_Web_Token
    2. https://auth0.com/blog/demystifying-jose-jwt-family/
    3. https://www.jwt.io
  6. Sessions and refresh tokens represent long-lived credentials; stealing them presents a major security risk, it is often very close to taking full control over the identity. That is why they must be stored in the most secure manner possible - it currently means HttpOnly and Secure Cookie (in the browser context). In this way, they are not accessible to any JavaScript code and transferred only when HTTPS is used: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies#block_access_to_your_cookies
  7. JWTs were designed to be stateless and in many contexts they are - especially when it comes to short-lived access tokens. But to support revocation of long-lived refresh tokens as well as other increased security measures, for various stolen token cases, some form of state is unavoidable.
  8. Public key cryptography, applied in virtually every authentication process:
    1. https://en.wikipedia.org/wiki/Public-key_cryptography
    2. https://en.wikipedia.org/wiki/Digital_signature
    3. https://www.youtube.com/watch?v=GSIDS_lvRv4
  9. Multi-Factor Authentication (MFA), most often used with just two factors:
    1. https://en.wikipedia.org/wiki/Multi-factor_authentication
    2. https://en.wikipedia.org/wiki/Authentication#Authentication_factors
    3. https://en.wikipedia.org/wiki/One-time_password
    4. https://en.wikipedia.org/wiki/Time-based_one-time_password
    5. https://en.wikipedia.org/wiki/SIM_swap_scam
    6. https://en.wikipedia.org/wiki/Biometrics
    7. https://en.wikipedia.org/wiki/WebAuthn
  10. Mutual authentication using cryptographic keys:
    1. https://en.wikipedia.org/wiki/Client_certificate
    2. https://en.wikipedia.org/wiki/Mutual_authentication
    3. https://www.cloudflare.com/learning/access-management/what-is-mutual-tls/
    4. https://en.wikipedia.org/wiki/Certificate_authority
    5. https://en.wikipedia.org/wiki/Public_key_infrastructure
  11. API Key: https://en.wikipedia.org/wiki/API_key and the Authorization header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Authorization
  12. Delegated Authentication concept:
    1. https://en.wikipedia.org/wiki/OpenID
    2. https://en.wikipedia.org/wiki/Identity_provider
    3. https://en.wikipedia.org/wiki/Single_sign-on
If you have valuable feedback, questions, comments, or you just want to get in touch, shoot me an email at [email protected].

See you there!

More posts