Skip to content

2 Autentificación

Introducción

A la hora de crear un servidor API REST tenemos que tener en cuenta que hay ciertas operaciones susceptibles que no deberían ser realizar por cualquier usuario. Para ello, es recomendable que exista un sistema de autentificación que permita verificar que tipo de usuario está realizando dicha operación y en caso de no permitírselo, bloquearlo.

Para poder realizar esa verificación existen diferentes técnicas, como:

  • Acceso a través de una apiKey: se puede considerar la menos segura, pero es útil para API REST amplias que requieran operaciones sencillas, como por ejemplo, obtener todos los libros de nuestra base de datos.
  • Acceso a través de JsonWebToken: Consiste en crear un token, que será enviado con la petición y se validará en el servidor. Puede ser utilizada para operaciones más vulnerables, como por ejemplo, crea un libro en nuestra base de datos.
  • Acceso a través de OAuth: Es un protocolo de autorización abierto que permite a los usuarios autorizar a aplicaciones de terceros a acceder a sus datos en otros servicios.

Clave API

Una API key (clave de API) es una cadena alfanumérica única que se utiliza para identificar y autorizar a un usuario, desarrollador o programa de llamada a una API.

Funciona como una credencial que permite el acceso a las funcionalidades o recursos ofrecidos por la API. Se puede utilizar para:

  • Autenticación: Verifica la identidad del usuario o aplicación que realiza la solicitud a la API.
  • Autorización: Determina el nivel de acceso que tiene el usuario o aplicación a los recursos de la API (lectura, escritura, etc.).
  • Rastreo y control: Permite al proveedor de la API identificar y monitorear el uso de la API por parte de diferentes usuarios o aplicaciones.

El usuario deberá crear la API Key y está será almacenada en una base de datos (para hacer esta operación, quizás se requiera una autentificación previa). Cuando el usuario realiza una operación, deberá aportar dicha clave, que será verificada posteriormente.

Proyecto API Key

En este proyecto, vamos a crear el acceso a una aplicación de forma sencilla a través de una API KEY. Para ello, lo primero que hacemos es configurar nuestro proyecto con express:

const app = express()
app.use(express.json())


const PORT = process.env.PORT || 1412

app.listen(PORT, () => {
    console.log(`Server running  on port ${PORT}`)
})

Realizamos la conexión a MongoDB:

connect(connectionString, { dbName: 'test' }).then(() => {
    console.log('Database connected')
}).catch(err => {
    console.error(err)
})

process.on('uncaughtException', error => {
    console.error(error)
    disconnect()
})

Configuramos el modelo:

const userSchema = new Schema({
    username: String,
    name: String,
    password: String,
    token: String,
    admin: Boolean
})

const User = model('User', userSchema)

Creamos una ruta que permita crear la API. En este caso, se crea un randomUUID() y se le añade un 1 o un 0 para comprobar si es o no administrador. En un proyecto más elaborado, se debería hacer de una forma diferente y crear una API Key a través de otro método de autentificación:

app.post('/api', async (req, res) => {
    const { username, password, name, admin } = req.body

    const user = await new User({ username, password, name, token: `${randomUUID()} ${admin ? 1 : 0}` }).save()

    if (!user) {
        res.status(400).json({ error: 'Something went wrong' })
        return
    }

    res.status(201).json(user)
})

Por último, creamos las rutas donde se requieran la API key, comprobando que:

  • El usuario ha proveído la API key como query de la request.
  • Comprobando si está registrada dicha API Key en la base de datos.
  • Comprobar si el usuario tiene permiso o no. En este ejemplo, solo podrá obtener los usuarios aquellos que provean una API key de administrador (con un 1 al final).
app.get('/users', (req, res) => {
    if (!req.query.apiKey) {
        res.status(401).json({ error: 'API Key is required' })
        return
    }

    // Validate API KEY
    const { apiKey } = req.query

    // Check if user exists
    const user = User.findOne({ token: apiKey })

    if (!user) {
        res.status(401).json({ error: 'Invalid API Key' })
        return
    }

    // Check if admin user
    const lastChar = apiKey[apiKey.length - 1]

    if (lastChar !== 1) {
        res.status(401).json({ error: 'API Key is provided but its not a admin api key' })
        return
    }

    const users = User.find()

    res.json(users)

})

Dicha comprobación se podría extrapolar en una función middleware y hacer uso de ella en las operaciones necesarias.