DEV Community

Cover image for Demystifying API Authentication and Authorization Methods
Dominic Azuka
Dominic Azuka

Posted on

Demystifying API Authentication and Authorization Methods

🚀 Excited to share my latest slides - a deep dive into API Security! From React.js on the client side to Node.js on the server side, join me in uncovering the art of securing APIs. Your gateway to understanding different authentication methods and authorization techniques. Let's fortify our code fortress together! 🛡️💻

1. API keys are like passwords for your apps. They're easy to use but not the most secure option. Great for public data access or low-security use cases.

Server Side (Node.js):

const express = require('express');
const app = express();

app.get('/api/resource', (req, res) => {
  const apiKey = req.headers.authorization.split(' ')[1];
  if (apiKey === 'YOUR_API_KEY') {
    res.json({ message: 'Access granted using API key!' });
  } else {
    res.status(401).json({ error: 'Unauthorized' });
  }
});

app.listen(3000);
Enter fullscreen mode Exit fullscreen mode

Client-Side (React.js):

fetch('/api/resource', {
  headers: {
    Authorization: 'API-Key YOUR_API_KEY'
  }
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

2. Basic auth uses a username and password combo, base64-encoded. It's simple, but sensitive info can be exposed. Useful for internal APIs or testing.

Server-Side (Node.js):

const express = require('express');
const app = express();

app.use(express.basicAuth({
  users: { 'username': 'password' }
}));

app.get('/api/resource', (req, res) => {
  res.json({ message: 'Access granted using Basic Auth!' });
});

app.listen(3000);
Enter fullscreen mode Exit fullscreen mode

Client-Side (React.js):

fetch('/api/resource', {
  headers: {
    Authorization: 'Basic ' + btoa('username:password')
  }
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

4. JWT tokens are self-contained, secure, and great for single sign-on (SSO) scenarios. They carry user claims and are widely used for identity verification.

Server-Side (Node.js):

const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();

app.get('/api/resource', (req, res) => {
  const token = req.headers.authorization.split(' ')[1];
  jwt.verify(token, 'SECRET_KEY', (err, decoded) => {
    if (err) {
      res.status(401).json({ error: 'Unauthorized' });
    } else {
      res.json({ message: 'Access granted using JWT token!', user: decoded.user });
    }
  });
});

app.listen(3000);
Enter fullscreen mode Exit fullscreen mode

Client-Side (React.js):

fetch('/api/resource', {
  headers: {
    Authorization: 'Bearer YOUR_JWT_TOKEN'
  }
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

5. OAuth 2.0 rules the world of third-party access. Ideal for apps using external services, it lets users grant limited access to their data.

Server-Side (Node.js):

const express = require('express');
const app = express();

app.get('/api/resource', (req, res) => {
  const accessToken = req.headers.authorization.split(' ')[1];
  // Validate and process the access token
  // ...
  res.json({ message: 'Access granted using OAuth 2.0 token!' });
});

app.listen(3000);
Enter fullscreen mode Exit fullscreen mode

Client-Side (React.js):

// Use a library like 'oauth2-client-js' to handle OAuth flow
// ...
Enter fullscreen mode Exit fullscreen mode

6. OAuth roles give structure to authorization. Resource owners control data access, clients request access, and authorization servers grant tokens.

Server-Side (Node.js):

const express = require('express');
const app = express();

app.post('/token', (req, res) => {
  // Process client credentials and generate access token
  // ...
  res.json({ access_token: 'YOUR_ACCESS_TOKEN' });
});

app.get('/api/resource', (req, res) => {
  const accessToken = req.headers.authorization.split(' ')[1];
  // Validate access token and roles
  // ...
  res.json({ message: 'Access granted with OAuth roles!' });
});

app.listen(3000);
Enter fullscreen mode Exit fullscreen mode

7. API tokens are managed by the API provider. Perfect for granting controlled access to specific parts of your API without sharing secrets.

Server-Side (Node.js):

const express = require('express');
const app = express();

app.get('/api/resource', (req, res) => {
  const apiToken = req.headers.authorization.split(' ')[1];
  // Validate API token
  // ...
  res.json({ message: 'Access granted using API token!' });
});

app.listen(3000);
Enter fullscreen mode Exit fullscreen mode

Client-Side (React.js):

fetch('/api/resource', {
  headers: {
    Authorization: 'Bearer YOUR_API_TOKEN'
  }
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

8. HMAC (Hash-based Message Authentication Code) adds a layer of security. Both client and server share a secret, and the server checks the hash to validate the request's authenticity.

Server-Side (Node.js):

const express = require('express');
const crypto = require('crypto');
const app = express();

app.get('/api/resource', (req, res) => {
  const providedHash = req.headers.authorization.split(' ')[1];
  const calculatedHash = crypto
    .createHmac('sha256', 'YOUR_SECRET_KEY')
    .update('data_to_hash')
    .digest('base64');
  if (providedHash === calculatedHash) {
    res.json({ message: 'Access granted using HMAC!' });
  } else {
    res.status(401).json({ error: 'Unauthorized' });
  }
});

app.listen(3000);
Enter fullscreen mode Exit fullscreen mode

Client-Side (React.js):

// HMAC is usually used on the server-side due to secret key
// ...
Enter fullscreen mode Exit fullscreen mode

9. OAuth 2.0 Scopes: Scopes define what an access token can do. Handy when an app needs specific permissions for different API endpoints.

Server-Side (Node.js):

const express = require('express');
const app = express();

app.get('/api/resource', (req, res) => {
  const accessToken = req.headers.authorization.split(' ')[1];
  // Validate access token and required scope
  // ...
  res.json({ message: 'Access granted with OAuth scopes!' });
});

app.listen(3000);
Enter fullscreen mode Exit fullscreen mode

Client-Side (React.js):

fetch('/api/resource', {
  headers: {
    Authorization: 'Bearer ACCESS_TOKEN_WITH_SCOPE'
  }
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
Enter fullscreen mode Exit fullscreen mode

Disclaimer: 🔑 Please note that the code examples above are simplified for educational purposes. In real-world scenarios, you'd need to implement error handling, security measures, and best practices. Client-side codes can also be enhanced with try-catch blocks, and HTTP requests can be managed using libraries like Axios.

Follow @dominicazuka for more related content.

beginnersguide #apisecurity #nodejs #reactjsdevelopment #webdevelopment #techtalks #securecoding #learnwithme #apikeys #basicauth #jwttokens #oauth2.0 #oauthroles #apitokens #hmac #oauthscopes #javascript #node.js #reactjs #securecoding #devsecops #frontenddevelopment #serverside #backenddevelopment

Top comments (0)