Skip to main content

Security Considerations

Token Expiration and Revocation​

Setting Expiration Times:

  • Purpose: Token expiration ensures that tokens are only valid for a specific period. This limits the time window in which a token can be used if compromised.
  • How to Set: When creating a JWT, set the exp (expiration) claim to define when the token will expire.

Example (Node.js with jsonwebtoken):

const token = jwt.sign(payload, secret, { expiresIn: '1h' }); // Token expires in 1 hour
  • Refresh Tokens: Implement refresh tokens to allow users to obtain a new access token without re-authenticating. Refresh tokens usually have a longer expiration time than access tokens.

Token Revocation Strategies:

  • Blacklisting: Maintain a list of revoked tokens. This requires storing token identifiers (e.g., jti) and checking this list on every request.

    Example (Node.js):

    const revokedTokens = new Set();

    function isTokenRevoked(token) {
    const decoded = jwt.decode(token);
    return revokedTokens.has(decoded.jti);
    }

    function revokeToken(token) {
    const decoded = jwt.decode(token);
    revokedTokens.add(decoded.jti);
    }
  • Short Expiry Times: Use short-lived access tokens combined with longer-lived refresh tokens. This reduces the risk if a token is compromised.

Securing the Token​

Using HTTPS:

  • Importance: Always use HTTPS to encrypt the data transmitted between the client and server. This prevents token interception by attackers.
  • Implementation: Ensure that your server is configured to support HTTPS and that clients access your API via https://.
important

Storing the Token Securely:

  • LocalStorage: Easy to use but vulnerable to XSS attacks.
  • SessionStorage: Similar to localStorage but data is cleared when the page session ends. Still vulnerable to XSS.
  • Cookies: Use cookies with the HttpOnly and Secure flags to mitigate XSS attacks and ensure the cookie is only sent over HTTPS.

Example (Setting HttpOnly and Secure Flags in Express.js):

app.use(cookieParser());

app.post('/login', (req, res) => {
const token = jwt.sign(payload, secret, { expiresIn: '1h' });
res.cookie('token', token, { httpOnly: true, secure: true });
res.send('Logged in');
});
note

Preventing Token Theft:

  • Content Security Policy (CSP): Implement CSP to reduce the risk of XSS attacks.
  • Regular Audits: Regularly review and update security practices and libraries.
  • Minimize Token Exposure: Avoid exposing tokens in URLs, and always send them in headers.

Choosing the Right Algorithm​

Symmetric (HMAC) vs. Asymmetric (RSA, ECDSA):

note
  • Symmetric (HMAC):

    • Algorithm: Uses the same secret key for both signing and verification (e.g., HS256).
    • Benefits: Faster and simpler since it requires only one key.
    • Use Cases: Suitable for scenarios where you control both the issuing and verifying parties, such as in internal systems.
  • Asymmetric (RSA, ECDSA):

    • Algorithm: Uses a pair of keys: a private key for signing and a public key for verification (e.g., RS256, ES256).
    • Benefits: More secure for scenarios where you need to share the verification key with multiple parties without exposing the signing key.
    • Use Cases: Suitable for public APIs or scenarios where the verification and issuance of tokens are handled by different entities.

Example (HMAC with jsonwebtoken):

const token = jwt.sign(payload, 'your-256-bit-secret', { algorithm: 'HS256' });

Example (RSA with jsonwebtoken):

const fs = require('fs');
const privateKey = fs.readFileSync('private.key');
const publicKey = fs.readFileSync('public.key');

const token = jwt.sign(payload, privateKey, { algorithm: 'RS256' });
const decoded = jwt.verify(token, publicKey);
tip
  1. Set Token Expiration: Define expiration times and use refresh tokens to manage sessions.
  2. Implement Revocation Strategies: Use blacklisting or short-lived tokens to handle token revocation.
  3. Secure Token Storage: Use HTTPS, store tokens securely, and prevent token theft.
  4. Choose the Right Algorithm: Select between symmetric and asymmetric algorithms based on your security needs and architecture.