To build a production-ready integration, follow these three patterns:
Token Storage
Always use .setPropertyStore() to persist tokens so users don't have to re-authorize every time. Use PropertiesService.getUserProperties() for user-specific access, or PropertiesService.getScriptProperties() for shared access.
Caching
To avoid hitting PropertiesService quotas, enable caching by adding .setCache(CacheService.getUserCache()). Ensure the cache scope matches your property store scope.
Locking
To prevent race conditions where multiple executions attempt to refresh an expired token simultaneously, use .setLock(LockService.getUserLock()). Ensure the lock scope matches your property store and cache scopes.
return OAuth2.createService('Foo')
.setPropertyStore(PropertiesService.getUserProperties())
.setCache(CacheService.getUserCache())
.setLock(LockService.getUserLock())