Integrate Google Classroom with Lovable by creating an Edge Function that calls the Google Classroom REST API using OAuth2 credentials stored in Cloud → Secrets. You can build teacher dashboards, assignment tracking tools, and student roster views. The integration requires a Google Cloud service account or OAuth2 client credentials, which authenticate every API call server-side from your Deno Edge Function.
Build custom Google Classroom dashboards and management tools in Lovable
Google Classroom is the dominant classroom management platform in K-12 education, with over 170 million users across more than 190 countries. Its REST API provides programmatic access to courses, coursework (assignments and questions), student submissions, announcements, and student rosters. This makes it possible to build custom interfaces — teacher dashboards that aggregate data across multiple classes, parent-facing portals that show assignment status, or administrative tools that give school leaders a bird's-eye view of classroom activity.
The Google Classroom API uses OAuth2 for authentication, which is more complex than simple API key auth. For teacher-facing apps where each teacher authorizes access to their own classes, you use the standard OAuth2 authorization code flow. For school-wide administrative tools that need to access data across all classrooms without individual teacher authorization, you use a service account with Google Workspace domain-wide delegation. The approach you choose depends on your use case — this tutorial covers both patterns.
All API calls in Lovable must go through a Deno Edge Function that manages the OAuth2 token exchange and injects credentials into Classroom API requests. This keeps your Google Cloud credentials — the client ID, client secret, and service account JSON — encrypted in Cloud → Secrets and invisible to users. The frontend calls your Edge Function with the desired Classroom action, and the Edge Function handles authentication and makes the actual API call to Google.
Integration method
Google Classroom does not have a Lovable shared connector. All API calls use OAuth2 authentication via a service account or user OAuth flow, with credentials stored encrypted in Cloud → Secrets. A Deno Edge Function handles token management and proxies Classroom API requests server-side, ensuring credentials never appear in frontend code. The Google Classroom API requires Google Workspace domain authorization for domain-wide delegation when accessing student data.
Prerequisites
- A Lovable account with at least one project created and deployed
- A Google account with access to Google Cloud Console (console.cloud.google.com)
- A Google Cloud project with the Google Classroom API enabled
- OAuth2 credentials (client ID + client secret) or a service account JSON key from Google Cloud
- For domain-wide access: a Google Workspace admin account to authorize domain-wide delegation
Step-by-step guide
Set up Google Cloud credentials and enable the Classroom API
Set up Google Cloud credentials and enable the Classroom API
Before storing any credentials in Lovable, you need to set up a Google Cloud project with the Classroom API enabled and create the appropriate credentials. Go to console.cloud.google.com and sign in. If you do not have a project, click 'Select a project' → 'New Project', give it a name, and click 'Create'. Once in your project, navigate to 'APIs & Services' → 'Library'. Search for 'Google Classroom API' and click on it. Click 'Enable'. For OAuth2 credentials (used when individual teachers authorize access to their own classes): go to 'APIs & Services' → 'Credentials'. Click 'Create Credentials' → 'OAuth 2.0 Client ID'. If prompted to configure the OAuth consent screen, click through the setup (choose 'Internal' for Google Workspace apps, 'External' for others). Set Application type to 'Web application'. Add your Lovable app's deployed URL as an Authorized redirect URI, plus https://[project-ref].supabase.co/functions/v1/google-classroom-auth/callback for the Edge Function callback. Download the credentials JSON file — you will need the client_id and client_secret values. For service account credentials (used for domain-wide access): click 'Create Credentials' → 'Service Account'. Name it, click 'Create and Continue', skip role assignment for now, and click 'Done'. Click on the service account you just created, go to 'Keys' tab, click 'Add Key' → 'Create New Key' → 'JSON'. Download the JSON key file. For domain-wide delegation (needed to access data across all classrooms in a Google Workspace domain): take note of the service account's client ID (numeric, found in the JSON key file under client_id). Your Google Workspace admin must go to admin.google.com → Security → API Controls → Domain-Wide Delegation → Add new, enter the client ID, and add the scopes: 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.
Pro tip: For a quick start, use the OAuth2 client credentials approach (not service account) — it requires less Google Workspace admin setup and works immediately for teachers who authorize the app. Add service account domain-wide delegation later when you need school-wide access.
Expected result: You have a Google Cloud project with the Classroom API enabled. You have either an OAuth2 client ID + secret (downloaded as JSON) or a service account key JSON file. These are ready to be stored in Lovable's Cloud → Secrets.
Store Google credentials in Cloud → Secrets
Store Google credentials in Cloud → Secrets
With your Google Cloud credentials ready, store them in Lovable's Cloud → Secrets panel. These encrypted environment variables will be accessed by your Edge Function via Deno.env.get() and are never exposed to client-side code. Click the '+' icon at the top of the Lovable editor to open the Cloud panel. Click the Secrets tab. Click 'Add new secret' and add the following (choose the set that matches your credential approach): For OAuth2 client credentials: - GOOGLE_CLIENT_ID — the client_id from your downloaded OAuth2 credentials JSON - GOOGLE_CLIENT_SECRET — the client_secret from your downloaded OAuth2 credentials JSON - GOOGLE_REDIRECT_URI — your Edge Function callback URL: https://[project-ref].supabase.co/functions/v1/google-classroom-auth/callback For service account credentials: - GOOGLE_SERVICE_ACCOUNT_JSON — paste the entire contents of the service account JSON key file as a single-line string (use a JSON minifier to remove whitespace) - GOOGLE_WORKSPACE_DOMAIN — your school's Google Workspace domain (e.g., myschool.edu) — needed for domain-wide impersonation To find your project reference, go to the Cloud tab → Database and look at the Supabase URL shown there — it contains your project reference in the format [project-ref].supabase.co. Service account JSON keys are long — typically 2,000-3,000 characters. Paste the entire minified JSON string as the secret value. Lovable's Secrets panel accepts large values. Verify the stored value starts with {"type":"service_account" when you hover over the secret (the panel shows the first few characters).
Pro tip: To minify your service account JSON for pasting into Secrets, paste the JSON into a browser console and run: JSON.stringify(JSON.parse(yourJsonString)). This produces a single-line version safe to store.
Expected result: All Google credentials are stored as secrets in Cloud → Secrets with masked values. The Edge Function will be able to access them via Deno.env.get('GOOGLE_CLIENT_ID') etc.
Create the Google Classroom API proxy Edge Function
Create the Google Classroom API proxy Edge Function
Now create the Edge Function that authenticates with Google and proxies Classroom API requests. This function accepts requests from your Lovable frontend, handles OAuth2 token generation (using either service account JWT auth or stored user access tokens), and forwards calls to the Google Classroom API. Paste this prompt into Lovable's chat: 'Create a Supabase Edge Function at supabase/functions/google-classroom-api/index.ts that proxies Google Classroom API requests. The function should: (1) Accept a POST request with body { endpoint: string, method: string, accessToken: string }. (2) Call https://classroom.googleapis.com/{endpoint} with the Authorization: Bearer {accessToken} header. (3) Return the Google Classroom API response with CORS headers. For service account auth, also accept a { serviceAccountMode: true, impersonateEmail: string } option that uses the GOOGLE_SERVICE_ACCOUNT_JSON secret to generate a JWT and obtain an access token from Google before making the API call.' The Google Classroom API base URL is https://classroom.googleapis.com/v1. Common endpoints: /courses (list all courses), /courses/{id}/students (student roster), /courses/{id}/courseWork (assignments), /courses/{id}/courseWork/{cwId}/studentSubmissions (submissions). For service account authentication, you need to create a JWT signed with the service account private key and exchange it for an access token at https://oauth2.googleapis.com/token. This is more complex than simple API key auth — the JWT must include the correct scopes, expiry time, and be signed with RS256 using the private key from the service account JSON. Deno has the Web Crypto API built in for this purpose.
Create a Supabase Edge Function at supabase/functions/google-classroom-api/index.ts. It accepts POST requests with body { endpoint: string, method: string, accessToken: string }. It calls https://classroom.googleapis.com/v1/{endpoint} with Authorization: Bearer {accessToken} header and returns the response as JSON with CORS headers. Handle pagination by accepting a pageToken parameter in the body and including it in the Google API call.
Paste this in Lovable chat
1// supabase/functions/google-classroom-api/index.ts2const corsHeaders = {3 'Access-Control-Allow-Origin': '*',4 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',5};67Deno.serve(async (req) => {8 if (req.method === 'OPTIONS') {9 return new Response('ok', { headers: corsHeaders });10 }1112 try {13 const { endpoint, method = 'GET', accessToken, pageToken, body: requestBody } = await req.json();1415 if (!accessToken) {16 return new Response(17 JSON.stringify({ error: 'Missing accessToken' }),18 { status: 401, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }19 );20 }2122 let url = `https://classroom.googleapis.com/v1/${endpoint}`;23 if (pageToken) {24 url += `${url.includes('?') ? '&' : '?'}pageToken=${encodeURIComponent(pageToken)}`;25 }2627 const fetchOptions: RequestInit = {28 method,29 headers: {30 'Authorization': `Bearer ${accessToken}`,31 'Content-Type': 'application/json',32 },33 };3435 if (requestBody && method !== 'GET') {36 fetchOptions.body = JSON.stringify(requestBody);37 }3839 const response = await fetch(url, fetchOptions);40 const data = await response.json();4142 return new Response(JSON.stringify(data), {43 status: response.status,44 headers: { ...corsHeaders, 'Content-Type': 'application/json' },45 });46 } catch (error) {47 return new Response(48 JSON.stringify({ error: error.message }),49 { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }50 );51 }52});Pro tip: Google Classroom API responses are paginated. Courses lists return nextPageToken in the response if there are more results. Your frontend should loop through pages until nextPageToken is absent. For most classrooms with under 100 courses, a single page is sufficient.
Expected result: The Edge Function is deployed and visible in the Cloud tab. It accepts POST requests with an access token and proxies them to the Google Classroom API. The function returns Classroom data as JSON to your frontend.
Implement the OAuth2 login flow for teachers
Implement the OAuth2 login flow for teachers
For teacher-facing apps where individual teachers authorize access to their own Google Classroom data, you need to implement the OAuth2 authorization code flow. This allows teachers to click 'Connect Google Classroom' in your Lovable app, authorize access in Google's consent screen, and have their access token stored securely for future API calls. Paste this prompt into Lovable's chat to generate the OAuth flow: 'Create an OAuth2 flow for Google Classroom: (1) A Connect Google Classroom button that redirects teachers to https://accounts.google.com/o/oauth2/v2/auth with client_id from GOOGLE_CLIENT_ID, redirect_uri from GOOGLE_REDIRECT_URI, scope as 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, response_type as code, and access_type as offline. (2) A callback Edge Function at supabase/functions/google-classroom-auth/index.ts that exchanges the authorization code for tokens at https://oauth2.googleapis.com/token and stores the access_token and refresh_token in the Supabase user profile. (3) A token refresh mechanism that calls the token endpoint with the refresh_token when the access_token expires.' Google access tokens expire after 1 hour. The refresh_token does not expire (unless the user revokes access) and can be used to get a new access_token. Store both in your Supabase user profiles table in columns google_access_token, google_refresh_token, and google_token_expires_at. Before each API call, check if the access token is expired and refresh it automatically. For security, never store the raw access token on the frontend — only in Supabase. When the frontend needs to call the Classroom API, it calls your Edge Function, which retrieves the stored token from Supabase using the Supabase service role key and injects it into the Google API call.
Add a Connect Google Classroom button to the settings page. Clicking it redirects to Google's OAuth2 authorization URL with the classroom.courses.readonly, classroom.rosters.readonly, and classroom.coursework.students.readonly scopes. Create a callback Edge Function that exchanges the auth code for tokens and stores them in the user's Supabase profile. Show Connected status with the teacher's Google email after authorization.
Paste this in Lovable chat
Pro tip: For complex Google Workspace integrations involving multiple schools or district-wide deployments, RapidDev's team can help configure domain-wide delegation with the correct scope mappings and impersonation logic for your specific Google Workspace setup.
Expected result: Teachers can click Connect Google Classroom, authorize via Google's consent screen, and return to your app in a connected state. Their access token and refresh token are stored in Supabase. Subsequent API calls succeed without re-authorization for up to the refresh token validity period.
Build teacher dashboard components
Build teacher dashboard components
With authentication working, build the React components that display Google Classroom data. The core dashboard shows a teacher's courses, and clicking a course reveals its assignments and student roster. Paste this prompt into Lovable's chat: 'Create a TeacherDashboard React component. On load, call the google-classroom-api Edge Function with endpoint "courses?courseStates=ACTIVE", passing the teacher's stored access token from their Supabase profile. Display courses in a grid: course name, section, enrollment code, and number of students. Add a student count by calling "courses/{id}/students" for each course. Clicking a course opens a detail view showing: (1) a roster table of student names and emails from the courses/{id}/students endpoint, (2) a list of active assignments from courses/{id}/courseWork?courseWorkStates=PUBLISHED sorted by dueDate, (3) for each assignment, a submission count vs total students fetched from courses/{id}/courseWork/{cwId}/studentSubmissions?states=TURNED_IN.' The Google Classroom API student submission states are: NEW (not viewed), CREATED (started), TURNED_IN (submitted), RETURNED (graded and returned), RECLAIMED_BY_STUDENT (recalled after submission). For tracking purposes, TURNED_IN and RETURNED both indicate submission. For the assignment list, display due dates in the teacher's local timezone. Google Classroom dueDate objects use a specific format: { year, month, day } and dueTime: { hours, minutes }. Combine these into a JavaScript Date object for display. Be aware of API quota limits: the Google Classroom API has a default quota of 500 read requests per 100 seconds per project. If you are loading many courses and their assignments simultaneously, implement a queue or sequential loading pattern rather than firing all requests in parallel.
Create a TeacherDashboard component that fetches active courses from the google-classroom-api Edge Function using the teacher's stored Google access token. Show courses as cards. Clicking a course shows: student roster table, active assignments list with due dates, and submission counts. Handle loading and error states. If the access token is expired, call a refresh-token Edge Function before retrying.
Paste this in Lovable chat
Pro tip: The Google Classroom API returns student profile photos in the userProfiles response. Use profile.photoUrl to show student avatars in the roster table — this makes the dashboard feel more personal and is especially appreciated in K-12 contexts where visual identification matters.
Expected result: The teacher dashboard loads their active Google Classroom courses. Clicking a course shows the student roster and assignment list with real data from Google Classroom. Submission counts are accurate and reflect the current state.
Common use cases
Teacher assignment tracking dashboard
Build a consolidated dashboard where teachers can see all their active courses in one place, view assignment submission counts, and track which students have not yet submitted. The dashboard pulls real-time data from Google Classroom via the API.
Create a teacher dashboard that calls my google-classroom-api Edge Function to fetch all the teacher's courses, then for each course fetch the active assignments and their submission counts. Show courses as cards with title, student count, and active assignment count. Clicking a course shows a list of assignments with: title, due date, submitted count vs total students, and a list of students who haven't submitted. Use OAuth2 with the teacher's access token stored in their Supabase session.
Copy this prompt to try it in Lovable
Parent-facing assignment status portal
Create a portal where parents can see their child's Google Classroom assignments across all classes — upcoming due dates, submission status, and grades. This requires domain-wide delegation to access student data.
Build a parent portal that shows a student's Google Classroom activity. Use the google-classroom-api Edge Function with a service account to fetch the student's courses, current assignments with due dates, and submission statuses. Show assignments in a calendar view with color coding: green for submitted, yellow for due soon, red for overdue. Parents log in with their own accounts and the student's Google Workspace email is linked in the Supabase profiles table.
Copy this prompt to try it in Lovable
School administrator course overview
Build an administrative dashboard that gives school leaders visibility into all classrooms in the school — active courses, teacher usage metrics, and assignment volume — using domain-wide delegation to access all classroom data.
Create an admin dashboard using my google-classroom-api Edge Function with service account auth to list all active courses across the school domain. Show: total active courses, courses per teacher, average students per course, and courses with no assignments posted in the last 7 days (flagged for follow-up). Let admins click any teacher to see their course list and recent activity.
Copy this prompt to try it in Lovable
Troubleshooting
API calls return 403 Forbidden with message 'The caller does not have permission'
Cause: The OAuth2 scopes authorized by the teacher do not include the scope needed for the API endpoint you are calling, or for service accounts, domain-wide delegation has not been configured for that scope.
Solution: Check the scope in your OAuth2 authorization URL. The scope must include all permissions needed: classroom.courses.readonly for course list, classroom.rosters.readonly for student lists, classroom.coursework.students.readonly for assignments and submissions. If the teacher authorized the app without the required scopes, they need to re-authorize. Have them disconnect (revoke access at myaccount.google.com/permissions) and reconnect. For service accounts, verify the scope is listed in your Google Workspace admin's domain-wide delegation settings.
OAuth2 callback returns 'redirect_uri_mismatch' error
Cause: The redirect URI in your OAuth2 authorization request does not exactly match an authorized redirect URI in your Google Cloud Console credentials configuration.
Solution: Go to console.cloud.google.com → APIs & Services → Credentials → your OAuth2 client → Authorized redirect URIs. Add the exact URL of your callback Edge Function: https://[project-ref].supabase.co/functions/v1/google-classroom-auth/callback (replacing [project-ref] with your actual Supabase project reference). Google requires exact matching — no trailing slashes, correct protocol (https not http). After saving, wait a few minutes for the change to propagate.
Google access token expires and API calls fail with 401 after one hour
Cause: Google OAuth2 access tokens expire after 3600 seconds (one hour). The app is not automatically refreshing the token using the stored refresh_token.
Solution: Implement automatic token refresh: before each API call, check if google_token_expires_at (stored in the user's Supabase profile) is within 5 minutes of expiry. If so, call your token refresh Edge Function that POSTs to https://oauth2.googleapis.com/token with grant_type=refresh_token and the stored refresh_token. Update the stored access_token and expires_at values. Add this check to your Edge Function so it handles refresh server-side rather than relying on the frontend to detect expiry.
Course data loads but student roster is empty even though students are enrolled
Cause: The classroom.rosters.readonly scope is not included in the OAuth2 authorization, or the teacher account does not have teacher-role access to the course (courses created by other teachers will not expose rosters).
Solution: Verify the scope in your OAuth2 authorization URL includes https://www.googleapis.com/auth/classroom.rosters.readonly. If the scope is correct, check whether the authenticated teacher is actually a teacher (not a co-teacher or domain admin) on that specific course. The Classroom API only returns student rosters for courses where the authenticated user has TEACHER role. Check the course's teacherFolder in the API response — the authenticated user's ID should appear there.
Best practices
- Request only the OAuth2 scopes your app actually needs — requesting minimal scopes increases the likelihood teachers will authorize the app and reduces security exposure
- Store Google OAuth2 tokens in Supabase with a user_id foreign key and never return raw tokens to the frontend — always proxy token-authenticated calls through Edge Functions
- Implement automatic token refresh before every API call rather than waiting for 401 errors — check token expiry server-side in the Edge Function
- Cache Classroom data in Supabase tables (courses, assignments, students) with a last_synced_at timestamp and serve cached data for dashboard loads — this avoids Google's 500 requests per 100 seconds quota on high-traffic dashboards
- Use Google Classroom's webhook/push notifications (via Google's Pub/Sub service) for real-time updates rather than polling the API — though this requires additional Google Cloud setup beyond this tutorial
- Add a clear disconnect flow so teachers can revoke access from both your app and Google's permissions page (myaccount.google.com/permissions) — this builds trust and is a GDPR/FERPA best practice in education contexts
- For school-wide deployments, get your Google Cloud OAuth consent screen verified by Google — unverified apps show a warning to users that can reduce adoption in school districts
Alternatives
Choose Canvas if you need an enterprise-grade LMS with richer API coverage, better grade book integration, and institutional deployment options beyond what Google Classroom offers.
Choose Moodle if you need a self-hosted open-source LMS where you control all data — Moodle's web services API offers comparable classroom management features without Google Workspace dependency.
Choose Schoology if your district uses Schoology as its primary LMS — it offers a dedicated K-12 REST API with OAuth 1.0a and better district-level reporting features.
Frequently asked questions
Does Google Classroom have a native Lovable connector?
No. Google Classroom is not one of Lovable's 17 shared connectors as of March 2026. You integrate it manually using Edge Functions with OAuth2 authentication. This tutorial covers both the individual teacher OAuth2 flow and the service account domain-wide delegation pattern for school-wide access.
Can I create assignments and post announcements via the API, or is it read-only?
The Google Classroom API supports creating and updating coursework (assignments), announcements, and materials — not just reading them. You need the classroom.coursework.me or classroom.coursework.students write scopes. This tutorial focuses on read operations since they cover the most common dashboard use case, but your Edge Function can proxy write requests using the same pattern.
How do I access data for students across an entire school district, not just one teacher's classes?
This requires a service account with Google Workspace domain-wide delegation. The Google Workspace admin must authorize the service account to impersonate users within the domain. Your Edge Function then generates a JWT signed with the service account credentials and requests tokens impersonating specific teachers or administrators. This setup is covered in Step 1 under the service account credential path.
Is student data from Google Classroom subject to FERPA or COPPA?
Yes. Student education records accessed via the Google Classroom API are protected by FERPA in the US, and data from students under 13 is additionally covered by COPPA. If you are building an app that stores or processes student data, you need a Data Processing Agreement with your school district, must limit data use to educational purposes, and should consult with a privacy attorney before deploying to K-12 schools. Storing student data in Supabase as described in this tutorial is technically possible but requires careful attention to data governance.
Why does the teacher's course list come back empty even after successful OAuth2 authorization?
The most common cause is that the OAuth2 scope only includes classroom.courses.readonly, which returns courses where the authenticated user is a teacher. If the teacher was added to a course as a co-teacher after initial enrollment, some courses may not appear depending on their role status. Also verify the course state filter — using ?courseStates=ACTIVE ensures only active (non-archived) courses are returned. Archived courses require the ARCHIVED state parameter.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation