Hello everyone!
I’m trying to develop my own plugin that implements third-party authentication using the OAuth protocol. During authorization, the users collection fields access_token and refresh_token are created or updated – these are external tokens, not internal NocoBase tokens.
My goal is to synchronize internal and external NocoBase tokens with the OAuth provider so that each time the internal NocoBase token is updated, the external token update process is triggered. My guess is that I can somehow intercept the internal NocoBase token update event in the plugin code and trigger the external token update process.
A rough idea of what I need in the code is below. Can anyone suggest something similar?
class MyOAuthPlugin extends Plugin {
async afterLoad() {
// Catch event like "auth.jwt.afterRenew"
this.app.on('auth.jwt.afterRenew', async (ctx, { userId, oldJti, newJti }) => {
this.app.logger.info(`NocoBase internal token renewed for user ${userId}. Old JTI: ${oldJti}, New JTI: ${newJti}`);
// refreshExternalTokens
await this.refreshExternalTokens(userId);
});
}
/**
* Refreshes external OAuth tokens for a user.
* @param userId NocoBase user ID
*/
async refreshExternalTokens(userId: number) {
const userRepository = this.app.db.getRepository('users');
const user = await userRepository.findOne({ filter: { id: userId } });
if (!user) {
this.app.logger.warn(`User ${userId} not found, cannot refresh external tokens.`);
return;
}
const currentRefreshToken = user.get('refresh_token');
if (!currentRefreshToken) {
this.app.logger.warn(`User ${userId} has no 'refresh_token' stored, skipping external token refresh.`);
return;
}
// --- YOUR THIRD-PARTY OAUTH PROVIDER TOKEN REFRESH LOGIC ---
// Replace YOUR_OAUTH_PROVIDER_TOKEN_ENDPOINT, YOUR_CLIENT_ID, YOUR_CLIENT_SECRET
// with your actual OAuth provider's data.
const oauthResponse = await axios.post('YOUR_OAUTH_PROVIDER_TOKEN_ENDPOINT', {
grant_type: 'refresh_token',
refresh_token: currentRefreshToken,
client_id: 'YOUR_CLIENT_ID',
client_secret: 'YOUR_CLIENT_SECRET',
// Additional parameters if required by your provider
});
const newAccessToken = oauthResponse.data.access_token;
// Refresh token might be updated or not. Use the new one if available, otherwise keep the old one.
const newRefreshToken = oauthResponse.data.refresh_token || currentRefreshToken;
// If the provider returns token expiration time, update it as well
const expiresIn = oauthResponse.data.expires_in;
// Update user record in NocoBase
await userRepository.update({
filter: { id: userId },
values: {
access_token: newAccessToken,
refresh_token: newRefreshToken,
// 'access_token_expires_at': new Date(Date.now() + expiresIn * 1000), // Example if storing expiration time
},
});
this.app.logger.info(`External tokens successfully updated for user ${userId}.`);
}
}