
https://thecopenhagenbook.com/
Server-side tokens
A server-side token is any long, random string that is stored on the server. It may be persisted in a database or in-memory data store (e.g. Redis) and is used for authentication and verification. A token can be validated by checking if it exists in storage. Examples include session IDs, email verification tokens, and access tokens.
Sessions
Throughout a user’s visit to your website, they will make multiple requests to your server. If you need to persist state, such as user preference, across those requests, HTTP doesn’t provide a mechanism for it. It’s a stateless protocol.
Sessions are a way to persist state in the server. It is especially useful for managing the authentication state, such as the client’s identity. We can assign each session with a unique ID and store it on the server to use it as a token. Then the client can associate the request with a session by sending the session ID with it. To implement authentication, we can simply store user data alongside the session.
It’s important that the session ID is sufficiently long and random, or else someone could impersonate other users by just guessing their session IDs. See the Server-side tokens guide for generating secure session IDs. Session IDs can be hashed before storage to provide an extra level of security.
Password authentication
-
Input validation
-
Checking for compromised passwords
-
Password storage
-
Argon2id
-
Scrypt
-
Bcrypt
-
Brute-force attacks
-
Error handling
-
Other considerations
Email verification
If your application requires user email addresses to be unique, email verification is a must. It discourages users from entering a random email address and, if password reset is implemented, allows users to take back accounts created with their email address. You may even want to block users from accessing your application’s content until they verify their email address.
Email addresses are case-insensitive. We recommend normalizing user-provided email addresses to lower case.
Password reset
A common approach to password reset is to use the user’s email address. The user enters their email and, if the email is valid, a password reset link is sent to the mailbox. This requires each user to have a unique email address – see the Email verification guide.
The email does not need to be verified before sending a reset link. You should even mark a user’s email address as verified if they reset their password.
Invalidate all existing sessions linked to the user when the user resets their password.
Generating random values
Pseudo-random generators often provided by the standard math package are fast but predictable. When dealing with cryptography, having access to a strong random generator is essential.
This page describes how to generate random strings and numbers from randomly generated bits.
OAuth
OAuth is a widely used protocol for authorization. It’s what’s behind “Sign in with Google” and “Sign in with GitHub.” It allows users to grant access to their resources on an external service, like Google, to your application without sharing their credentials. Instead of implementing a password-based auth, we can replace it with OAuth to let a third-party service handle authentication. You can then get the user’s profile and use that to create users and sessions.
In a basic OAuth flow, the user is redirected to a third-party service, the service authenticates the user, and the user is redirected back to your application. An access token for the user is made available which allows you to request resources on behalf of the user.
It requires 2 server endpoints in your application:
Login endpoint (GET): Redirects the user to the OAuth provider.
Callback endpoint (GET): Handles the redirect from the OAuth provider.
There are multiple versions of OAuth, with OAuth 2.0 being the latest one. This page will only cover OAuth 2.0, specifically the authorization code grant type, as standardized in RFC 6749. The implicit grant type is deprecated and should not be used.
Multi-factor authentication (MFA)
MFA is when a user is required to input more than just a password to authenticate. There are mainly 5 types of factors:
-
Something you know: Passwords
-
Something you have: Device, email address, SMS
-
Something you are: Biometrics
-
Somewhere you are
-
Something you do
WebAuthn
The Web Authentication (WebAuthn) standard allows users to authenticate with their device, either with a PIN code or biometrics. The private key is stored in the user’s device, while the public key is stored in your application. Applications can authenticate users by verifying signatures. Since credentials are bounded to the user’s device (or devices) and brute-forcing is impossible, a potential attacker needs physical access to a device.
WebAuthn is usually used in 2 ways – with passkeys or security tokens. While they don’t have a strict definition, passkeys usually refer to credentials that can replace passwords and stored in the authenticator (resident keys). Security tokens, on the other hand, are meant to be used as a second factor, after authenticating with a password. Credentials for 2FA are usually encrypted and stored in the relying party’s server. In both cases, they are a more secure alternative to existing methods.
Cross-site request forgery (CSRF)
CSRF attacks allow an attacker to make authenticated requests on behalf of users when credentials are stored in cookies.
When a client makes a cross-origin request, the browser sends a preflight request to check whether the request is allowed (CORS). However, for certain “simple” requests, including form submissions, this step is omitted. And since cookies are automatically included even for cross-origin requests, it allows a malicious actor to make requests as the authenticated user without ever directly stealing the token from any domain. The same-origin policy prohibits cross-origin clients from reading responses by default, but the request still goes through.
Open redirect
Open redirect is a vulnerability where your application allows a user to control a redirect.
For example, you may want to redirect the user back to their original page after they sign in. To achieve this, you add a redirect_to URL query parameter to the login page and form. When a user signs in, the user is redirected to the location defined in redirect_to.
But what if you accept any redirect location without validating it?
This may seem harmless at first, but it makes it significantly easier to scam users. The user could be redirected to an identical site made by an attacker and be prompted to enter their password again.
Elliptic curve digital signature algorithm (ECDSA)
ECDSA is a digital signature algorithm using elliptic-curve cryptography. A private key is used to sign a message and a public key is used to verify the signature.
The message is hashed with algorithms like SHA-256 before signing.