Skip to main content
RapidDev - Software Development Agency
bubble-integrationsBubble API Connector

Google Classroom

Google Classroom requires full OAuth 2.0 with a 1-hour access token that must be refreshed via a Backend Workflow. Build an OAuth authorization page in Bubble, store the refresh token in a private User field with strict privacy rules, build a RefreshClassroomToken Backend Workflow that exchanges the refresh token for a new access token before every session, then call the Classroom API endpoints for courses, rosters, and submissions. Use an Internal consent screen type to bypass Google's weeks-long app review.

What you'll learn

  • How to set up a Google Cloud project with the Classroom API enabled and OAuth credentials configured
  • How to choose between Internal and External OAuth consent screen types and why Internal bypasses app review
  • How to build an OAuth authorization page in Bubble that initiates the Google consent flow
  • How to build a RefreshClassroomToken Backend Workflow for automatic access token renewal
  • How to store refresh tokens securely in Bubble's database with strict privacy rules
  • How to call the Classroom API for courses, student rosters, assignments, and submissions
  • How to handle the userId-vs-email gap in Classroom's submissions endpoint
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Advanced19 min read6–10 hoursEducationLast updated July 2026RapidDev Engineering Team
TL;DR

Google Classroom requires full OAuth 2.0 with a 1-hour access token that must be refreshed via a Backend Workflow. Build an OAuth authorization page in Bubble, store the refresh token in a private User field with strict privacy rules, build a RefreshClassroomToken Backend Workflow that exchanges the refresh token for a new access token before every session, then call the Classroom API endpoints for courses, rosters, and submissions. Use an Internal consent screen type to bypass Google's weeks-long app review.

Quick facts about this guide
FactValue
ToolGoogle Classroom
CategoryEducation
MethodBubble API Connector
DifficultyAdvanced
Time required6–10 hours
Last updatedJuly 2026

Google Classroom in Bubble: conquering OAuth 2.0 for education apps

Google Classroom sits at the intersection of two complex systems: Google's OAuth 2.0 authorization framework and a REST API with restricted scopes that require app verification for public apps. For most Bubble developers building school or district tools, understanding these systems upfront saves days of troubleshooting.

First, the auth model. Google Classroom does not offer a simple API key. Every access requires an OAuth 2.0 flow: the user (typically a teacher or admin) clicks 'Connect with Google' in your Bubble app, is redirected to Google's consent screen, approves access, and is sent back to your Bubble app with an authorization code. Your Backend Workflow exchanges that code for an access token (valid 1 hour) and a refresh token (valid until revoked). The access token is used in all API calls; the refresh token is stored and used to obtain new access tokens automatically.

Second, the scope classification. Google Classroom API scopes are classified as 'restricted' by Google — meaning if you publish your app publicly to users outside your Google Workspace domain, Google requires a security audit before allowing more than 100 users. For school-specific apps, the solution is simple: set the OAuth consent screen type to 'Internal' — this restricts the app to users within your Google Workspace for Education domain but completely bypasses the verification requirement.

Third, the data model. The Classroom API returns courseIds and userIds (internal Google identifiers), not email addresses. Building a student-name lookup table from the roster endpoint is mandatory for any UI that displays names.

With these three concepts understood, the Bubble implementation is straightforward to build step by step.

Integration method

Bubble API Connector

Call the Google Classroom REST API (classroom.googleapis.com/v1) using OAuth 2.0 Bearer tokens, with a Backend Workflow handling token refresh every 3600 seconds.

Prerequisites

  • A Google Cloud Console project with the Google Classroom API enabled (console.cloud.google.com)
  • OAuth 2.0 credentials (Web Application type) created in Google Cloud Console with your Bubble app URL added as an authorized redirect URI
  • A Google Workspace for Education domain (for Internal consent screen type, which bypasses app verification)
  • Bubble Starter plan or higher — Backend Workflows are required for token exchange and refresh; not available on Free plan
  • The API Connector plugin installed in your Bubble app (Plugins tab → Add plugins → search 'API Connector' by Bubble)
  • Basic familiarity with Bubble's Custom States and URL parameters (used throughout the OAuth flow)

Step-by-step guide

1

Set up Google Cloud project and OAuth credentials

Go to console.cloud.google.com. Create a new project (or select an existing one) named after your Bubble app. **Enable the Classroom API:** In the left sidebar, go to APIs & Services → Library. Search for 'Google Classroom API' and click Enable. **Configure the OAuth Consent Screen:** Go to APIs & Services → OAuth consent screen. - **User Type:** Select **Internal** if your school uses Google Workspace for Education — this restricts the app to your domain's users but completely bypasses Google's weeks-long verification review for restricted scopes. Select External only if you need users from outside your domain (and be prepared for the verification process). - Fill in App name, User support email (your school email), Developer contact information. - Under Scopes, click 'Add or Remove Scopes' and add: - `https://www.googleapis.com/auth/classroom.courses.readonly` - `https://www.googleapis.com/auth/classroom.rosters.readonly` - `https://www.googleapis.com/auth/classroom.coursework.students.readonly` - Save and continue. **Create OAuth 2.0 Credentials:** Go to APIs & Services → Credentials → Create Credentials → OAuth 2.0 Client ID. - Application type: **Web application** - Name: 'Bubble App' - Authorized redirect URIs: add `https://your-bubble-app.bubbleapps.io/oauth-callback` (replace with your actual Bubble app URL plus the callback page name you'll create) - Click Create. Copy the **Client ID** and **Client Secret** — you'll use these in Bubble.

Pro tip: For school-domain apps, always choose 'Internal' user type on the OAuth consent screen. This single choice eliminates the requirement for Google's security review — saving weeks of waiting. Internal apps are restricted to users within your Google Workspace domain, which is exactly what a school app needs.

Expected result: The Google Classroom API is enabled in your Cloud project. An OAuth consent screen is configured with Internal type and the three classroom scopes. You have a Client ID and Client Secret ready to use in Bubble.

2

Build the OAuth authorization page in Bubble

Create a new page in Bubble named `oauth-callback`. This page will handle the final step of the OAuth flow — receiving Google's authorization code and exchanging it for tokens. **Store your OAuth credentials in Bubble:** Do not hardcode the Client ID and Client Secret in workflows. Instead, go to Settings → Environment Variables (or use a Bubble 'Config' Data Type with admin-only privacy rules). Store: - `google_client_id` — your OAuth Client ID (this can be semi-public, but keep it in config for easy updates) - `google_client_secret` — your OAuth Client Secret (this MUST be Private; never expose it in client-side code) **Build the authorization redirect:** On your main page, add a 'Connect Google Classroom' button. Its workflow action should open a URL in a new tab: ``` https://accounts.google.com/o/oauth2/v2/auth ?client_id=YOUR_CLIENT_ID &redirect_uri=https://your-app.bubbleapps.io/oauth-callback &response_type=code &scope=https://www.googleapis.com/auth/classroom.courses.readonly https://www.googleapis.com/auth/classroom.rosters.readonly https://www.googleapis.com/auth/classroom.coursework.students.readonly &access_type=offline &prompt=consent ``` The `access_type=offline` parameter is critical — without it, Google will not return a refresh token. The `prompt=consent` forces the consent screen every time, which ensures you always receive a refresh token (without it, Google may skip issuing a new one if the user has authorized before). **Capture the authorization code on the callback page:** On the `oauth-callback` page, add a page-load workflow. In the workflow, use 'Get data from URL → code' to capture the `code` URL parameter that Google appends to your redirect URI. Store this in a Custom State: `authorization_code` (text). Immediately trigger a Backend Workflow named 'ExchangeCodeForTokens' passing the authorization_code value.

google-oauth-authorize-url.txt
1https://accounts.google.com/o/oauth2/v2/auth?client_id=<YOUR_CLIENT_ID>&redirect_uri=https://your-app.bubbleapps.io/oauth-callback&response_type=code&scope=https://www.googleapis.com/auth/classroom.courses.readonly%20https://www.googleapis.com/auth/classroom.rosters.readonly%20https://www.googleapis.com/auth/classroom.coursework.students.readonly&access_type=offline&prompt=consent

Pro tip: Test the OAuth flow in a regular browser window first — the flow may not work correctly inside Bubble's editor preview pane due to iframe restrictions on Google's consent screen. Always test on the published version of your app.

Expected result: Clicking 'Connect Google Classroom' opens Google's consent screen in a new browser tab. After the user approves, they are redirected to your Bubble oauth-callback page with a 'code' URL parameter visible in the address bar.

3

Build the token exchange and refresh Backend Workflows

These Backend Workflows handle the server-side token operations. They require Bubble Starter plan or higher. **ExchangeCodeForTokens Backend Workflow:** Go to Settings → API → enable 'This app exposes a Workflow API'. Open Backend Workflows tab. Create a new API Workflow named 'ExchangeCodeForTokens' with parameter: `auth_code` (text). In the API Connector, add a new API Group called 'Google OAuth'. Add a call: - Name: Exchange Code for Tokens - Method: POST - URL: `https://oauth2.googleapis.com/token` - Body parameters (application/x-www-form-urlencoded): - `code`: `<auth_code>` (dynamic) - `client_id`: `<YOUR_CLIENT_ID>` (not Private — Client IDs are semi-public) - `client_secret`: `<YOUR_CLIENT_SECRET>` (mark **Private**) - `redirect_uri`: `https://your-app.bubbleapps.io/oauth-callback` - `grant_type`: `authorization_code` Initialize with real values from your OAuth flow. In the ExchangeCodeForTokens workflow, call this API. Then save the response fields: - `Result's access_token` → store in a User private field `classroom_access_token` - `Result's refresh_token` → store in a User private field `classroom_refresh_token` (this is precious — store it permanently) - `Result's expires_in` → compute expiry time: Current date/time + expires_in seconds; store in `classroom_token_expiry` **RefreshClassroomToken Backend Workflow:** Create a second Backend Workflow named 'RefreshClassroomToken'. No parameters needed — it acts on Current User. In the API Connector Google OAuth group, add another call: - Name: Refresh Access Token - Method: POST - URL: `https://oauth2.googleapis.com/token` - Body: `client_id`, `client_secret` (Private), `refresh_token` = `<refresh_token>` (dynamic), `grant_type` = `refresh_token` In the RefreshClassroomToken workflow: call Refresh Access Token, set `refresh_token` to Current User's classroom_refresh_token. Save `Result's access_token` to User's classroom_access_token and update classroom_token_expiry. Set privacy rules on both User fields (`classroom_access_token`, `classroom_refresh_token`): visible only when Current User is the User record.

google-refresh-token-call.json
1{
2 "method": "POST",
3 "url": "https://oauth2.googleapis.com/token",
4 "headers": {
5 "Content-Type": "application/x-www-form-urlencoded"
6 },
7 "body": {
8 "client_id": "<YOUR_CLIENT_ID>",
9 "client_secret": "<private>",
10 "refresh_token": "<refresh_token>",
11 "grant_type": "refresh_token"
12 }
13}

Pro tip: Add a conditional check before every Classroom API call: if Current User's classroom_token_expiry is in the past (or within 5 minutes), call the RefreshClassroomToken Backend Workflow first. This prevents 401 errors mid-session from expired access tokens.

Expected result: Both Backend Workflows exist and can be triggered. After a user completes the OAuth flow, their classroom_access_token and classroom_refresh_token are stored in private User fields. The RefreshClassroomToken workflow can be called to get a fresh access token anytime.

4

Configure the Classroom API calls in Bubble API Connector

Add a new API Group in the API Connector called 'Google Classroom'. Set the Base URL to `https://classroom.googleapis.com/v1`. Add a shared header at the API Group level: - **Authorization**: `Bearer <access_token>` — mark this header value as **Private** BUT note that the token itself is dynamic (it changes per user). You'll override this at the call level using a dynamic value from the User record. **Call 1 — List Courses:** - Name: List Courses - Method: GET - URL append: `/courses` - URL parameters: `teacherId` = `me` (to list current user's courses), `pageSize` = `20`, `courseStates` = `ACTIVE` - Use as: Data - Initialize with your access token in the Authorization header **Call 2 — List Students (course roster):** - Name: List Students - Method: GET - URL append: `/courses/<courseId>/students` - Parameters: `courseId` = dynamic - Initialize with a real courseId **Call 3 — List CourseWork (assignments):** - Name: List CourseWork - Method: GET - URL append: `/courses/<courseId>/courseWork` - Parameters: `courseId` = dynamic **Call 4 — List Student Submissions:** - Name: List Submissions - Method: GET - URL append: `/courses/<courseId>/courseWork/<courseWorkId>/studentSubmissions` - Parameters: `courseId` = dynamic, `courseWorkId` = dynamic IMPORTANT: Submissions return `userId` (Google's internal ID), NOT email addresses. To display student names, you must pre-fetch the course roster (Call 2) and build a name lookup. Store the roster in a local Bubble Data Type `ClassroomStudent` with `google_user_id`, `full_name`, and `email_address` fields. Use a Search to match submission userId to the local roster.

classroom-submissions-call.json
1{
2 "method": "GET",
3 "url": "https://classroom.googleapis.com/v1/courses/<courseId>/courseWork/<courseWorkId>/studentSubmissions",
4 "headers": {
5 "Authorization": "Bearer <access_token>"
6 },
7 "params": {
8 "courseId": "<courseId>",
9 "courseWorkId": "<courseWorkId>"
10 }
11}

Pro tip: Google Classroom paginates using a 'nextPageToken' field in the response body. Store this token in a Custom State and wire a 'Load More' button to re-run the query with 'pageToken' set. For most courses with fewer than 250 items, a single page covers the full dataset — Classroom's default page size is 20; increase to 100 or 250 via the pageSize parameter.

Expected result: All four Classroom API calls are initialized successfully. You can see course data, student rosters, assignment lists, and submission records in the Initialize call responses. The userId field in submissions is visible — you know this needs to be mapped to student names via the roster.

5

Build the Classroom dashboard UI

Create a page `classroom-dashboard` in Bubble. This page requires the user to be logged in and have a valid classroom_access_token. **Token freshness check on page load:** Add a page-load workflow: if Current User's classroom_token_expiry is in the past → call RefreshClassroomToken Backend Workflow → continue after completion. If classroom_refresh_token is empty → redirect to oauth-callback page to re-authorize. **Course list Repeating Group:** Add a Repeating Group with Type: 'Google Classroom - List Courses response'. Data Source: 'Get data from external API → Google Classroom - List Courses', setting the Authorization header dynamically to `Bearer [Current User's classroom_access_token]`. In each cell, display: course name, section (if available), enrollment count, and a 'View Assignments' button navigating to an assignments page with the courseId as a URL parameter. **Student submission matrix (assignment detail page):** Create a second page `classroom-course` with URL parameter `course_id`. - Fetch assignments: 'Get data from external API → List CourseWork' with courseId = URL's course_id parameter - For each assignment, fetch submissions using the List Submissions call - Pre-load the course roster using List Students and store in a page-level temporary state (a list of student objects) - For each submission's userId, search the temporary roster state to find the matching student name **Handle school-wide access:** If your Bubble app needs school-wide visibility (all teachers' courses), the teacher's own OAuth token can only see their own courses. You need a Google Workspace domain admin to authorize the app — the domain admin's refresh token grants access to all courses across all teachers. Store the admin token separately (in a Config record, not a User record) and use it for school-wide queries.

Pro tip: WU economy tip: fetching submissions for 10 courses × 5 assignments each = 50 API calls in workflows. Bubble charges WU per workflow run. For large course loads, cache assignment and submission data locally in Bubble DB with a 'Last synced' timestamp, and offer a 'Refresh Data' button for on-demand updates rather than fetching live on every page view.

Expected result: The classroom dashboard displays the logged-in teacher's active courses. Clicking a course shows the assignment list. Clicking an assignment shows a submission status list with student names (resolved via the roster lookup). Token refresh happens automatically if the access token is expired.

6

Set privacy rules and test the complete OAuth flow

Before going live, lock down all sensitive data with Bubble privacy rules. **Privacy rules for User fields:** Go to Data tab → User → Privacy. Add rules: - `classroom_access_token`: This User is visible when Current User is the User (only the user themselves can read their own token) - `classroom_refresh_token`: same rule — Current User is the User - `classroom_token_expiry`: same rule **Privacy rules for locally cached Classroom data:** If you store course or submission data in Bubble Data Types: - ClassroomStudent records: visible when Current User is the teacher who fetched them (add a `teacher_ref` field on the record) - Submission data: visible when Current User is the student OR the teacher (not visible to unrelated users) **Full end-to-end test:** 1. Open your published Bubble app in a fresh browser session (not the editor) 2. Click 'Connect Google Classroom' 3. Verify Google's consent screen appears with your app name and the three scopes listed 4. Approve access. Verify you land on the oauth-callback page with a code parameter 5. Verify classroom_access_token and classroom_refresh_token are saved to the User record (check via Bubble's App Data tab) 6. Navigate to the dashboard — verify courses appear 7. Wait 1 hour OR temporarily set classroom_token_expiry to a past time. Reload the page. Verify the token refreshes automatically without any user action 8. Check Bubble's Logs tab → Workflow logs. Confirm Backend Workflows ran successfully and no errors appear in the token exchange or refresh calls RapidDev's team has built district-wide Google Classroom dashboards on Bubble — if you need help structuring OAuth flows for multi-teacher or admin-scope access patterns, book a free scoping call at rapidevelopers.com/contact.

Pro tip: If a user revokes your app's access in their Google account settings, the refresh token becomes invalid and the RefreshClassroomToken workflow will fail with a 401. Add error handling in the RefreshClassroomToken workflow: if the API call fails, clear the classroom_refresh_token field and redirect the user to re-authorize via the OAuth flow.

Expected result: The full OAuth flow works on the published app. Privacy rules prevent any user from seeing another user's tokens or classroom data. Token refresh happens automatically. The Classroom dashboard loads course data, assignment lists, and submission rosters correctly.

Common use cases

School attendance and progress tracker

A K-12 school builds a Bubble app where teachers see all their Google Classroom courses in a unified dashboard. For each course, they can view assignment submission rates, identify students who haven't submitted work, and send nudge notifications — all without leaving the Bubble app. The app pulls live submission data from the Classroom API and aggregates it across all assignments in the course.

Bubble Prompt

Build a Bubble app that connects to a teacher's Google Classroom via OAuth, lists all their active courses, and for each course shows an assignment completion matrix — which students submitted each assignment and which haven't. Include a 'Send Reminder' button that triggers a Bubble workflow.

Copy this prompt to try it in Bubble

District-wide course catalog and enrollment viewer

A school district's instructional coordinator builds a Bubble app using a Google Workspace admin account token to view all courses across all teachers in the district. The app shows course distribution by subject, enrollment numbers by grade level, and flags courses with low activity — giving district leadership insights not available in the standard Classroom interface.

Bubble Prompt

Create a Bubble dashboard for district administrators that uses a Google Workspace admin OAuth token to list all Google Classroom courses across the district, grouped by subject area, with enrollment counts and last-activity dates displayed.

Copy this prompt to try it in Bubble

Student portfolio and grade aggregator

A high school builds a student-facing Bubble app where students log in with their school Google account, connect their Classroom via OAuth, and see an aggregated view of their submitted work, grades, and upcoming due dates across all their courses. The app caches assignment data locally for offline access and highlights late submissions.

Bubble Prompt

Build a student portal in Bubble where students connect their Google Classroom account via OAuth. The app should show all their enrolled courses, list assignments per course with due dates and submission status, and display returned grades in a clean card layout.

Copy this prompt to try it in Bubble

Troubleshooting

Google consent screen is blocked or shows 'Access blocked: This app has not completed the Google verification process'

Cause: The OAuth consent screen is set to 'External' user type and the app has not completed Google's security review for restricted Classroom scopes. Any public app using restricted scopes is blocked until verified.

Solution: If your app is for users within a single Google Workspace for Education domain (a school or district), switch the OAuth consent screen to 'Internal' type in Google Cloud Console → APIs & Services → OAuth consent screen → Edit App → User Type → Internal. This restricts the app to your domain users but completely bypasses the verification requirement.

The token exchange Backend Workflow returns an error or the refresh token is empty after the OAuth flow

Cause: The access_type=offline parameter or prompt=consent parameter is missing from the authorization URL. Without access_type=offline, Google does not issue a refresh token. Without prompt=consent, Google may skip issuing a new refresh token if the user has authorized the app before.

Solution: Ensure the authorization URL includes both access_type=offline and prompt=consent as query parameters. If the URL is correct, re-authorize by clearing the user's existing classroom_refresh_token and going through the OAuth flow again — Google will issue a fresh refresh token.

API calls return 401 Unauthorized after the app has been working for a while

Cause: The access token has expired (access tokens are valid for 3600 seconds / 1 hour). The RefreshClassroomToken workflow was not called before the API request.

Solution: Add a page-load workflow on every page that uses Classroom API data: check if Current User's classroom_token_expiry is less than Current date/time. If yes, call RefreshClassroomToken Backend Workflow and wait for it to complete before loading API data. You can also add a check before individual API calls in workflows using an 'Only when' condition combined with a pre-refresh step.

Submissions Repeating Group shows Google userIds but no student names

Cause: The Classroom API's studentSubmissions endpoint returns userId (Google's internal identifier), not email addresses or display names. This is by design — names require a separate roster lookup.

Solution: Before rendering the submissions view, call the List Students endpoint for the course to fetch the roster. Store the roster as a list of objects in a Custom State on the page. In each submission cell, use a Search or filtered list to match the submission's userId to the roster state and display the profile name from the matching student record.

Backend Workflows option is not available or 'Schedule API Workflow' is missing

Cause: Backend Workflows require a paid Bubble plan. The Free plan does not include this feature, and both the token exchange and token refresh workflows require Backend Workflows.

Solution: Upgrade to Bubble's Starter plan ($32/month) or higher. Then go to Settings → API → enable 'This app exposes a Workflow API'. The Backend Workflows section will appear in the left sidebar.

A teacher's token can only see their own courses — school-wide access is needed

Cause: Google Classroom API access is scoped to the authorizing user's account. A teacher's OAuth token can only retrieve courses where they are the teacher. School-wide access requires a Google Workspace domain admin account to authorize the app.

Solution: Have a Google Workspace domain admin go through the OAuth authorization flow in your Bubble app. Their access token and refresh token grant access to all courses in the domain. Store the admin's tokens separately (in a Config record in Bubble's DB with admin-only privacy rules) and use them specifically for school-wide queries — not for individual teacher dashboards.

Best practices

  • Always use 'Internal' OAuth consent screen type for school-domain apps — it restricts access to your Google Workspace domain but bypasses Google's weeks-long app verification review for restricted Classroom scopes.
  • Store OAuth refresh tokens in a private Bubble User field with strict privacy rules ('This User is visible when Current User is the User'). The refresh token grants long-term API access equivalent to the user's Google Classroom account — protect it accordingly.
  • Include access_type=offline AND prompt=consent in every authorization URL. Without offline, no refresh token is issued. Without prompt=consent, Google may skip issuing a new refresh token for previously authorized users.
  • Always call RefreshClassroomToken at the start of every user session and before any long-running workflow that makes multiple Classroom API calls. Access tokens expire after 3600 seconds — a token that was valid when the user logged in may expire mid-session.
  • Cache course rosters (student name → userId mappings) locally in Bubble's database. The submissions endpoint only returns userIds, and fetching the full roster on every page view is expensive in WU. Store the roster on first load and refresh it on demand.
  • Set WU-efficient patterns for large course loads: batch assignment and submission fetches into scheduled Backend Workflows rather than fetching live on page load. Display a 'Last synced' timestamp and offer a 'Refresh' button for on-demand updates.
  • Handle token revocation gracefully: if the RefreshClassroomToken workflow fails with a 401, clear the user's stored tokens and redirect them to re-authorize via the OAuth flow rather than showing a generic error page.
  • For teacher tokens that need to access student submission data, verify that the classroom.coursework.students.readonly scope was included in the authorization URL. Missing scopes silently return empty result sets rather than explicit permission errors.

Alternatives

Frequently asked questions

Do I need to complete Google's app verification to use the Classroom API?

Not necessarily. If your app is for users within a single Google Workspace for Education domain (a specific school or district), set the OAuth consent screen to 'Internal' user type. Internal apps are restricted to your domain but completely bypass the verification requirement — you can launch immediately. External apps (for users across different Google accounts) require verification if you use restricted Classroom scopes and have more than 100 test users.

Why does the Classroom API return userId instead of student names and emails?

Google Classroom's studentSubmissions endpoint returns Google's internal userId identifiers for privacy and consistency reasons. To display student names, you must call the /courses/{courseId}/students endpoint separately to retrieve the course roster, which includes profile names and email addresses for each student. Map submission userIds to the roster to display human-readable names in your Bubble UI.

Can one teacher's Bubble integration see other teachers' courses?

No. A teacher's OAuth token only provides access to courses where that teacher is listed as the teacher. To access all courses in a Google Workspace for Education domain, a domain admin must authorize the app. Admin tokens can list courses across all teachers and view submissions domain-wide. Store admin tokens separately from teacher tokens in your Bubble app.

How long does the refresh token last?

Google refresh tokens for Workspace accounts generally do not expire as long as they are used at least once every 6 months and the user has not revoked access. However, they can be invalidated if: the user revokes app access in their Google account settings, the user changes their Google password, the OAuth consent screen changes significantly, or your app is flagged by Google. Build error handling for refresh token failures that redirects users through the OAuth flow again.

Can I use Google Classroom with Bubble's Free plan?

The API Connector can technically make Classroom API calls on the Free plan — but the entire OAuth flow (token exchange and token refresh) requires Backend Workflows, which are only available on paid Bubble plans. Without Backend Workflows, you cannot securely handle the OAuth authorization code exchange (which must POST your client_secret server-side). Bubble's Starter plan ($32/month) is the minimum requirement for a secure Classroom integration.

What happens if a student's Google account is removed from the Workspace domain?

The student's roster entry will no longer appear in subsequent calls to the /courses/{courseId}/students endpoint. However, their submission records will still exist in Classroom's API with the original userId. Your locally cached ClassroomStudent records in Bubble DB will retain the old data — add a periodic sync that refreshes the roster and marks removed students as inactive to keep your data consistent.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Integrations are where projects stall

We wire Bubble integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.