How to restrict Multi-Tenant Bookings + Google Accounts Separation
How to restrict Multi-Tenant Bookings + Google Accounts
This article is the second in a three-part series on building architectural booking syncs:
- Part 1: Google Cloud Infrastructure & OAuth Configuration
- Part 2: Managing Tenant Isolation & Shared Team Calendars (This Post)
- [Part 3: Bidirectional Client Syncing with FullCalendar & Java] (/blog/2026/google-calendar-and-full-calendar-bidirection/)
When building a multi-tenant booking engine that integrates with Google Calendar, a common challenge is ensuring that each tenant’s bookings are properly isolated while allowing them to connect their Google accounts for calendar syncing. In this article, we will explore how to restrict multi-tenant bookings and manage Google account connections effectively in a Java backend architecture.
The Challenge of Multi-Tenancy and Google Accounts
In a multi-tenant booking engine where the need to connect Google accounts to a pre-existing tenancy, you need to separate application tenants from Google accounts. Building from the previous post ()[2026-05-23-setting-up-google-calendar-api-oauth2-for-multi-tenant-booking-engines]
In this scenario, you don’t restrict Google’s permissions directly via OAuth scopes (since Google has no concept of your application’s database boundaries). Instead, you enforce tenant isolation and calendar consistency programmatically inside your Java backend database schema and logic.
Here is the exact architecture, database design, and code pattern to achieve this workflow smoothly.
1. The Multi-Tenant Calendar Schema
To allow an Admin to authorize a single Google account for the entire workspace while ensuring team members are synced to the exact same calendar name, your database needs to map tenant_id to its respective Google OAuth credentials and a unique google_calendar_id.
+——————+ 1 : 1 +————————–+ | tenants | ——————–> | tenantgoogle_configs | +——————+ +————————–+ | * tenantid (PK) | | * tenant_id (FK, PK) | | - company_name | | - encrypted_refresh_token| | | | - google_email | | | | - target_calendar_id | +——————+ +————————–+ | | | 1 : N | 1 : 1 (Contextual) v v +——————+ +————————–+ | users / team | | Google Workspace | +——————+ +————————–+ | * user_id (PK) | | - “Company Schedule” | | - tenant_id (FK) | | (Shared Calendar ID) | | - email | +————————–+ Your data table layout should look like this:
CREATE TABLE tenant_google_configs (
tenant_id VARCHAR(255) PRIMARY KEY,
google_email VARCHAR(255) NOT NULL,
encrypted_refresh_token TEXT NOT NULL, -- Stored securely
target_calendar_id VARCHAR(255), -- The specific unique calendar ID generated by Google
calendar_name VARCHAR(100) DEFAULT 'Company Bookings'
);
2. Step-by-Step Implementation Flow
Step 1: Admin Authorizes the App
When the Admin connects their Google Account, they go through the standard OAuth loop. Your Java backend intercepts the callback, receives the refresh_token, and stores it under that specific tenant_id.
Step 2: Programmatically Create the “Named” Calendar
Instead of pushing bookings to the Admin’s raw primary calendar (which would mix personal and business data), your Java backend uses the Admin’s token to create a secondary calendar with your standardized application name.
import com.google.api.services.calendar.Calendar;
import com.google.api.services.calendar.model.Calendar;
public class GoogleCalendarProvisioner {
public String provisionSharedTenantCalendar(Calendar googleCalendarService, String companyName) throws IOException {
// 1. Define the uniform calendar layout
com.google.api.services.calendar.model.Calendar secondaryCalendar =
new com.google.api.services.calendar.model.Calendar();
secondaryCalendar.setSummary(companyName + " Bookings");
secondaryCalendar.setTimeZone("America/New_York"); // Adjust contextually
// 2. Execute creation on Google's Infrastructure
com.google.api.services.calendar.model.Calendar createdCalendar =
googleCalendarService.calendars().insert(secondaryCalendar).execute();
// 3. Return the generated ID (looks like: c_xxxxxxxxx@group.calendar.google.com)
return createdCalendar.getId();
}
}
You save this returned target_calendar_id directly into your tenant_google_configs table.
Step 3: Pushing Bookings for Team Members
When a customer schedules an appointment with Team Member B, Team Member B does not need to connect their personal Google account.
Your Java scheduling service looks up the workspace context:
-
Fetch the encrypted_refresh_token and the target_calendar_id using the current tenant_id.
-
Decrypt the token and build your authorized Google Calendar client.
-
Construct the event, adding the team member’s name or corporate email directly inside the Event Description or Title (e.g., “Massage Therapy By [Name]”).
-
Execute events.insert(targetCalendarId, event).
Because it is targeted directly to the saved target_calendar_id, the booking automatically routes straight into the corporate calendar the Admin established.
3. Restricting Scopes Safely for this Model
Because you are creating and managing a custom secondary calendar on behalf of the business workspace, you can safely use the broader event scope discussed previously:
https://www.googleapis.com/auth/calendar.events
This allows your application to execute management actions inside that specific custom secondary calendar box without hitting permission blocks, while keeping the rest of the Admin’s personal schedule completely isolated from your code execution pathways.
Conclusion
By decoupling your calendar generation from individual team member credentials and linking it straight to the tenant configuration, you eliminate a significant amount of user friction. Team members don’t have to navigate complex individual authentication screens, and administrators maintain total centralized visibility over their company’s availability.
When establishing this data relationship in your Java backend, always ensure the refresh_token is strongly encrypted at rest and that your application isolates the specific target_calendar_id on every query. This setup guarantees a secure, reliable, and scalable sync architecture that grows perfectly alongside your multi-tenant ecosystem.