Security
What's the best way of storing these credentials?
There are many options, but I'm looking for the safest one.
No matter where you store it, always do it in an encrypted format. This way even if leaked they cannot be reused, unless the encryption key is also leaked.
Refresh Token Persistence
Storing the encrypted tokens in the database isn't my favorite choice, but the most persistent one.
You can do it with sessions, JWT tokens or directly into a database. Let's see the options...
Laravel Sessions
If you are using user sessions in your Laravel application you can store it encrypted in the session for each user.
Laravel Sessions
Since HTTP driven applications are stateless, sessions provide a way to store information about the user across multiple requests. Laravel ships with a variety of session backends that are accessed through an expressive, unified API. Support for popular backends such as Memcached, Redis, and databases is included out of the box.
Laravel also supports to store the session in encrypted cookies.
JWT Tokens
If you are using JWT tokens then your are probably using a JWS token, then if so store it encrypted in a JWS claim or even better, use JWE tokens.
The claim in a JWT token is a key/value pair in the payload of the JWT token. The JWT Token is composed by header.payload.signature. Payload example:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
JWS
A JSON Web Signature (abbreviated JWS) is an IETF-proposed standard (RFC 7515) for signing arbitrary data.[1] This is used as the basis for a variety of web-based technologies including JSON Web Token.
JWE
JSON Web Encryption (JWE) is an IETF standard providing a standardised syntax for the exchange of encrypted data, based on JSON and Base64.[1] It is defined by RFC7516. Along with JSON Web Signature (JWS), it is one of the two possible formats of a JWT (JSON Web Token). JWE forms part of the JavaScript Object Signing and Encryption (JOSE) suite of protocols.
You can learn more about JWT at https://jwt.io/introduction.
Databases
Use the database more convenient for you, aka the one already available in your application. Don't introduce Redis just to store the refresh token, but if you already have Redis in use, then it can be an alternative, but I would just store it encrypted in the database you already store the user info. After all refreshing a token is not an operation you do in every request, therefore performance may not be so critical here.