There are many articles dedicated to the OAuth access token exchange for user login, and then using that token with an API. While there are complexities around how to get the token from an authorization provider, there are many articles and examples which can help. This is the simple case.
When there is one user, one UI, and one service, things are simple. Access control is still necessary, roles are still necessary, permissions configuration is still necessary. But the user is logged in, access tokens are valid, and responses are quick and synchronous. This happens rarely, more frequently, some part of the requests your application has will be long running or executed when a user is offline. Some of these are as simple as a email distribution for new features. In those cases, service client api keys can be used to allow one service to authorize another service. These actions are performed in the context of a calling service.
Long running transactions
However, when service access needs to be done on behalf of a user, then the service needs to have a valid, non-expired access token. And this token may need to be valid, days, weeks, or months later. To make sure a request only accesses the appropriate resources, these should be done as the service impersonating the user, and as a matter of fact, the calling service may not even have direct access to the resources owned by another service client. This happens more frequently when the data is owned by a third party, or a secure area of your application platform, and it isn't enough to have your authorization provider (which may or may not be Authress) since that third party won't know about your authorization capabilities.
The authorization code flow
Using the OAuth flow a service can receive a long lived refresh token a secured service can use to reauthenticate with a third party api and allow it to make subsequent authorized calls.
Extending the model to microservices
When there is only one service that needs access to these refresh tokens, a simple database with user <=> refresh
token can work. Since there is only one refresh token, and every new refresh token requires a new user interaction, only one service can manage these tokens. In many cases there is more than one service, and more than one of these needs access to these tokens. In those cases, having a central Credentials service can reduce the friction. However, this introduces the need to secure that service. In those cases, it is necessary to create a Credentials resource scoped to the user, which would allow other services to request access to these refresh tokens.
Create the necessary role
Create the necessary credentials related roles.
Assign the role to the relevant clients
Then, assign the the new credentials related roles to the appropriate internal clients.
Credentials access check
Finally, when a request comes in to access these refresh tokens or other credentials make the appropriate access check:
import { AuthressClient } from '@authress/sdk';
const authressClient = new AuthressClient({ authressApiUrl: 'https://auth.yourdomain.com' });
async function getUserCredentials(serviceClientCallerId, userId) {
// Check that caller has access to the relevant credential for a user
await authressClient.userPermissions.authorizeUser(serviceClientCallerId,
`/user-credentials/refresh-tokens/users/${userId}`,
'credentials:read');
// If the caller has access then lookup the credentials
const storedRefreshToken = await GetRefreshTokenForUser(userId);
// Get an access token for the refresh token
const accessToken = await GetAccessTokenFromRefreshToken(storedRefreshToken, {...});
return {
statusCode: 200,
body: { accessToken }
};
}
Going further
Building the credentials service is easier said than done though, while the permissions is a huge part, security of the data the is even more important. Security of the endpoints as well as encryption of the data (at rest, in transit, and in memory if not actively being used). For this reason to make it simple, Authress provides automatic credential handling of refresh tokens through any configured Authress OAuth provider connection.