Google Classroom API lets your Bolt.new app read courses, assignments, and rosters from Google Classroom. The integration uses OAuth 2.0 with education scopes — authentication callbacks only work on deployed sites, not in Bolt's WebContainer preview. Build a Next.js API route to handle the OAuth flow, then deploy to Netlify or Bolt Cloud to complete testing.
Building Educational Tools on Top of Google Classroom
Google Classroom is used by over 150 million students and teachers worldwide, making it one of the most data-rich educational platforms available. Its REST API exposes courses, coursework (assignments and questions), student rosters, grades, and submissions — everything you need to build supplementary tools like assignment trackers, progress dashboards, parent portals, or automated grading aids.
The integration path uses OAuth 2.0, Google's standard protocol for accessing user data. When a teacher signs in, they're redirected to Google's consent screen, grant permission for specific Classroom scopes, and return to your app with an authorization code. Your server exchanges this code for tokens, which are then used to call the Classroom API on their behalf.
Important: some Classroom API scopes are restricted and require your Google Cloud project to go through Google's OAuth verification process. Scopes for viewing courses and coursework you own work with any Google account. Scopes that access other people's data (student rosters, all submissions in a course) require Google Workspace for Education accounts and may trigger Google's OAuth app review process. This tutorial covers the common teacher-facing scopes that work without verification.
Integration method
The Google Classroom API uses OAuth 2.0 for authentication, which requires a publicly accessible callback URL that WebContainers cannot provide during development. You configure OAuth credentials in Google Cloud Console, build Next.js API routes to handle the authorization code exchange and API calls, and test the complete flow only after deploying to Netlify or Bolt Cloud. Once authenticated, your app can read courses, coursework, and student rosters.
Prerequisites
- A Bolt.new account with a Next.js project created
- A Google account with access to Google Cloud Console (console.cloud.google.com)
- A Google Classroom account with at least one course (for testing)
- A deployed Bolt Cloud or Netlify URL to register as the OAuth redirect URI
- Basic understanding of OAuth 2.0 authorization code flow
Step-by-step guide
Enable Google Classroom API and Create OAuth 2.0 Credentials
Enable Google Classroom API and Create OAuth 2.0 Credentials
Start at Google Cloud Console (console.cloud.google.com). Create a new project or select an existing one. Navigate to APIs & Services → Library, search for 'Google Classroom API', and click Enable. You'll also need to enable the 'Google People API' if you plan to access student profile information. Next, configure the OAuth consent screen: go to APIs & Services → OAuth consent screen. Choose 'External' if you want any Google account to log in (required for testing), or 'Internal' if you're building for a specific Google Workspace for Education domain. Fill in the app name, support email, and developer contact. On the Scopes step, add the scopes you need: start with '.../auth/classroom.courses.readonly' for listing courses and '.../auth/classroom.coursework.me.readonly' for viewing assignments. Do NOT add student-roster or submission-reading scopes unless you need them — they trigger a full Google OAuth verification review. Now create credentials: APIs & Services → Credentials → Create Credentials → OAuth Client ID. Select 'Web application'. Under 'Authorized redirect URIs', add your deployed URL (e.g., https://your-app.netlify.app/api/auth/callback/google). You'll update this after deployment if you don't have a URL yet. Download the credentials JSON — you'll need the client_id and client_secret.
Pro tip: Start with the minimum scopes needed. Adding more scopes later is easy; removing them requires informing users and updating your OAuth consent screen. Restricted scopes like 'classroom.rosters' require Google Workspace for Education accounts.
Expected result: Google Classroom API is enabled in your GCP project. OAuth consent screen is configured. You have a client_id and client_secret from the downloaded credentials JSON.
Configure Environment Variables and Install Dependencies
Configure Environment Variables and Install Dependencies
In your Bolt.new project, add the OAuth credentials and configuration to your .env file. You'll need the Google client ID and secret (server-side only — no NEXT_PUBLIC_ prefix), the OAuth callback URL (your deployed domain), and a session secret for encrypting tokens stored in cookies. For the Google Classroom API calls, you'll use the googleapis npm package, which provides typed clients for all Google APIs including Classroom. For session management, iron-session provides encrypted, stateless cookie sessions that work well with Next.js API routes and don't require a database to store tokens. Prompt Bolt to install these packages and set up the basic project structure.
Install the googleapis and iron-session npm packages. Create a lib/google-auth.ts file that exports a function to create an OAuth2 client using GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET environment variables. Also create a lib/session.ts file with iron-session configuration for storing the Google access_token and refresh_token in an encrypted HTTP-only cookie.
Paste this in Bolt.new chat
1# .env file additions2# OAuth credentials — server-side only, never NEXT_PUBLIC_3GOOGLE_CLIENT_ID=your_client_id.apps.googleusercontent.com4GOOGLE_CLIENT_SECRET=GOCSPX-your_client_secret5# Update this to your deployed URL before testing OAuth6GOOGLE_REDIRECT_URI=https://your-app.netlify.app/api/auth/callback7# Generate a random 32+ character string for session encryption8SESSION_SECRET=replace_with_32_character_random_string_here9# OAuth scopes — space-separated10GOOGLE_SCOPES=https://www.googleapis.com/auth/classroom.courses.readonly https://www.googleapis.com/auth/classroom.coursework.me.readonlyPro tip: Generate a secure SESSION_SECRET with: openssl rand -base64 32 (or use a password manager to generate a 32+ character random string).
Expected result: Dependencies installed, .env file configured, and lib/ files created without TypeScript errors.
Build OAuth 2.0 Authorization and Callback API Routes
Build OAuth 2.0 Authorization and Callback API Routes
The OAuth flow requires two API routes: one that redirects users to Google's authorization page, and one that handles the callback with the authorization code and exchanges it for tokens. The authorization route generates the Google OAuth URL with your configured scopes, sets the access_type to 'offline' (required to receive a refresh token for long-lived access), and includes 'prompt: consent' to ensure you get a refresh token even if the user has previously authorized. Without 'prompt: consent', Google only sends a refresh token on the first authorization. The callback route receives the authorization code from Google, exchanges it for access and refresh tokens, stores them in an encrypted session cookie, and redirects the user to the dashboard. Token storage in a session cookie means no database is required for basic use — but if you need tokens to persist across sessions or for server-to-server calls without a logged-in user, store them in your database instead.
Create two Next.js API routes: 1) /api/auth/login that generates a Google OAuth URL and redirects the user to Google's consent screen. 2) /api/auth/callback that receives the authorization code, exchanges it for tokens using the googleapis OAuth2 client, stores the tokens in an iron-session cookie, and redirects to /dashboard. Also create a /api/auth/logout route that clears the session. Use TypeScript.
Paste this in Bolt.new chat
1// app/api/auth/login/route.ts2import { NextResponse } from 'next/server';3import { google } from 'googleapis';45function getOAuthClient() {6 return new google.auth.OAuth2(7 process.env.GOOGLE_CLIENT_ID,8 process.env.GOOGLE_CLIENT_SECRET,9 process.env.GOOGLE_REDIRECT_URI10 );11}1213export async function GET() {14 const oauth2Client = getOAuthClient();15 const scopes = (process.env.GOOGLE_SCOPES ?? '').split(' ');1617 const authUrl = oauth2Client.generateAuthUrl({18 access_type: 'offline',19 scope: scopes,20 prompt: 'consent', // Always get refresh_token21 });2223 return NextResponse.redirect(authUrl);24}2526// app/api/auth/callback/route.ts27import { NextResponse } from 'next/server';28import { google } from 'googleapis';2930export async function GET(request: Request) {31 const url = new URL(request.url);32 const code = url.searchParams.get('code');33 const error = url.searchParams.get('error');3435 if (error || !code) {36 return NextResponse.redirect(new URL('/?error=auth_failed', request.url));37 }3839 try {40 const oauth2Client = new google.auth.OAuth2(41 process.env.GOOGLE_CLIENT_ID,42 process.env.GOOGLE_CLIENT_SECRET,43 process.env.GOOGLE_REDIRECT_URI44 );4546 const { tokens } = await oauth2Client.getToken(code);47 // Store tokens in session cookie (implement with iron-session)48 // tokens.access_token, tokens.refresh_token, tokens.expiry_date49 50 return NextResponse.redirect(new URL('/dashboard', request.url));51 } catch (err) {52 console.error('OAuth callback error:', err);53 return NextResponse.redirect(new URL('/?error=token_exchange_failed', request.url));54 }55}Pro tip: Always include 'prompt: consent' in the auth URL options. Without it, Google only sends a refresh_token the first time a user authorizes, making it impossible to get one for returning users unless they explicitly revoke access first.
Expected result: OAuth routes are created. Visiting /api/auth/login redirects to Google's consent screen. After authorizing, Google redirects to /api/auth/callback with a code parameter.
Fetch and Display Google Classroom Data
Fetch and Display Google Classroom Data
With tokens stored in the session, you can now make authenticated Classroom API calls. Create an API route that fetches the user's courses and coursework, then build a React component that displays this data. The googleapis package provides a typed classroom client. You initialize it with the OAuth2 client that has tokens set, then call classroom.courses.list() to get all courses, classroom.courses.courseWork.list() to get assignments in a specific course, and classroom.courses.courseWork.studentSubmissions.list() to get submission data. For rate limits, the Classroom API allows 500 requests per 100 seconds per project and 100 requests per 100 seconds per user. For a dashboard that loads multiple courses' assignments at once, use sequential requests with small delays rather than Promise.all() on many simultaneous calls.
Create a /api/classroom/courses route that fetches the authenticated user's Google Classroom courses and returns them as JSON. Create a /api/classroom/coursework/[courseId] route that fetches assignments for a specific course. Build a Dashboard React component that calls these APIs, shows a loading state, and displays courses in a card grid with course name, section, and teacher name. Clicking a course card shows its assignments.
Paste this in Bolt.new chat
1// app/api/classroom/courses/route.ts2import { NextResponse } from 'next/server';3import { google } from 'googleapis';45export async function GET(request: Request) {6 // Get tokens from session cookie7 // (Replace with your actual session retrieval logic)8 const accessToken = 'YOUR_ACCESS_TOKEN_FROM_SESSION';9 const refreshToken = 'YOUR_REFRESH_TOKEN_FROM_SESSION';1011 try {12 const oauth2Client = new google.auth.OAuth2(13 process.env.GOOGLE_CLIENT_ID,14 process.env.GOOGLE_CLIENT_SECRET,15 process.env.GOOGLE_REDIRECT_URI16 );17 oauth2Client.setCredentials({18 access_token: accessToken,19 refresh_token: refreshToken,20 });2122 const classroom = google.classroom({ version: 'v1', auth: oauth2Client });2324 const coursesResponse = await classroom.courses.list({25 courseStates: ['ACTIVE'],26 pageSize: 20,27 });2829 const courses = coursesResponse.data.courses ?? [];30 return NextResponse.json({ courses });31 } catch (error: unknown) {32 if ((error as { code?: number }).code === 401) {33 return NextResponse.json({ error: 'Token expired — please re-authenticate' }, { status: 401 });34 }35 console.error('Classroom API error:', error);36 return NextResponse.json({ error: 'Failed to fetch courses' }, { status: 500 });37 }38}Pro tip: The googleapis OAuth2 client automatically refreshes expired access tokens using the refresh token. Set up a token refresh listener (oauth2Client.on('tokens', ...)) to save the new access token back to your session or database.
Expected result: The /api/classroom/courses endpoint returns a JSON array of the authenticated user's active courses. The dashboard component displays course cards correctly.
Deploy and Complete OAuth Testing
Deploy and Complete OAuth Testing
Since OAuth callbacks require a registered redirect URI, you must deploy before the complete authentication flow works. The Bolt preview URL (containing webcontainer-api.io) cannot be registered as an authorized URI in Google Cloud Console. Deploy to Netlify by connecting your GitHub repository in Netlify's dashboard and adding all environment variables: GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI (set to your Netlify URL + /api/auth/callback), and SESSION_SECRET. After your first deploy, you'll know your Netlify URL — go back to Google Cloud Console → APIs & Services → Credentials → your OAuth client → edit → add the new redirect URI. Once deployed, test the flow by visiting your Netlify URL, clicking login, authenticating with a Google account that has Classroom access, and verifying that courses appear in the dashboard. Check the browser's Network tab to confirm API calls return 200 responses with real course data.
Add a login page to my app with a 'Sign in with Google' button that navigates to /api/auth/login. Add a nav bar that shows the user's email (fetched from the session) when logged in and a logout button. If the user is not authenticated, redirect them from /dashboard to the login page.
Paste this in Bolt.new chat
Pro tip: After deploying to Netlify, update GOOGLE_REDIRECT_URI in Netlify's environment variables to match your exact deployed URL (e.g., https://your-app-name.netlify.app/api/auth/callback). Then redeploy for the new variable to take effect.
Expected result: Visiting the deployed Netlify URL, clicking 'Sign in with Google', and completing the OAuth flow successfully redirects to the dashboard showing real Google Classroom courses.
Common use cases
Teacher Assignment Dashboard
Build a consolidated dashboard showing all active assignments across multiple Google Classroom courses. Teachers can see upcoming due dates, submission counts, and grading status without switching between individual classes — useful for teachers managing 5+ sections simultaneously.
Build a teacher dashboard that connects to the Google Classroom API. After OAuth login, display all the teacher's courses in a grid. When clicking a course, show the list of coursework (assignments and questions) with due dates and the number of submissions turned in. Use Next.js API routes for the OAuth flow and Classroom API calls, and store the refresh token in an encrypted cookie.
Copy this prompt to try it in Bolt.new
Student Progress Tracker
Create a student-facing app that shows all their courses, pending assignments, and submitted work in a timeline view. Students can see what's due this week across all classes in one place, reducing missed assignments from notification overload in the Classroom interface.
Create a student assignment tracker using the Google Classroom API. After the student authenticates with their Google account, fetch all their enrolled courses and the coursework in each course. Show assignments grouped by due date with a 'submitted' or 'pending' badge. Filter to show only assignments due in the next 7 days by default.
Copy this prompt to try it in Bolt.new
Parent Portal for Course Visibility
Build a read-only portal where parents can view their child's course list and upcoming assignments without logging into the student's account. This requires the student to authenticate once and the app to store their tokens securely, displaying sanitized assignment information.
Build a parent portal where students can authenticate with Google Classroom, and the app saves their course and assignment data to a database. Parents receive a share link to view upcoming assignments without needing Google accounts. Include an API route that fetches fresh data from Classroom every hour using the stored refresh token.
Copy this prompt to try it in Bolt.new
Troubleshooting
Google OAuth shows 'redirect_uri_mismatch' error after authentication
Cause: The redirect URI registered in Google Cloud Console does not exactly match the URL your app sends in the OAuth request. Even minor differences (trailing slash, http vs https, different path) cause this error.
Solution: Go to Google Cloud Console → APIs & Services → Credentials → your OAuth client. Verify the exact URI in Authorized redirect URIs matches process.env.GOOGLE_REDIRECT_URI exactly, including protocol, domain, and path. Ensure you're testing on the deployed URL, not the Bolt preview URL.
OAuth flow works but tokens expire and API calls start returning 401
Cause: Access tokens expire after 1 hour. Without a refresh token flow implemented, expired tokens are not automatically renewed.
Solution: Implement a token refresh listener on the OAuth2 client. When the client automatically refreshes the access token, save the new token to your session or database.
1oauth2Client.on('tokens', (tokens) => {2 if (tokens.access_token) {3 // Save updated access_token to session or database4 console.log('Token refreshed:', tokens.access_token);5 }6});'Request had insufficient authentication scopes' when calling courses.courseWork.list()
Cause: The classroom.coursework.me.readonly scope only allows reading the authenticated user's own assignments. If you're trying to read all assignments in a course as a teacher, you need the classroom.coursework.readonly scope.
Solution: Add the classroom.coursework.readonly scope to GOOGLE_SCOPES in your .env file and update the authorized scopes in Google Cloud Console. Users will need to re-authorize to grant the new scope.
1GOOGLE_SCOPES=https://www.googleapis.com/auth/classroom.courses.readonly https://www.googleapis.com/auth/classroom.coursework.readonlyAPI calls fail with 'The caller does not have permission' for student roster or submission endpoints
Cause: Scopes like classroom.rosters and accessing other users' submissions require Google Workspace for Education accounts. Personal Gmail accounts cannot access these scopes.
Solution: Test with a Google Workspace for Education account (usually a school-issued email). If your use case requires these scopes with personal accounts, apply for Google's OAuth verification process, which involves a security assessment.
Best practices
- Request only the minimum OAuth scopes needed — start with courses.readonly and coursework.me.readonly, adding broader scopes only when required
- Always set access_type: 'offline' and prompt: 'consent' in the OAuth URL to ensure you receive a refresh token for long-lived access
- Store refresh tokens securely — they are long-lived credentials that can be used to generate access tokens indefinitely until revoked
- Implement a token refresh listener to automatically save new access tokens when the OAuth client refreshes them
- Test on a deployed domain (not Bolt's WebContainer preview) since OAuth callbacks require a stable, registered redirect URI
- Handle 401 errors from the Classroom API by redirecting users to re-authenticate — access tokens expire and refresh tokens can be revoked
- Cache course and coursework data for a few minutes to avoid hitting Classroom API rate limits (500 requests/100 seconds per project)
- Be transparent with users about what data your app accesses — the OAuth consent screen lists all scopes, but a clear in-app explanation builds trust
Alternatives
Canvas has a more permissive REST API with token-based auth (no OAuth required for personal access), making it easier to build integrations without going through Google's OAuth setup process.
Schoology's API covers similar LMS functionality and is widely used in US K-12 districts as a Google Classroom alternative — worth targeting if your users are in districts that use it.
Moodle is the dominant open-source LMS for higher education globally, with a REST API that uses token authentication — good for university or self-hosted educational platform integrations.
Frequently asked questions
Can I test the Google Classroom integration in Bolt's preview window?
You can develop and test the API route code structure in Bolt's preview, but the OAuth authentication flow requires deployment. Google's OAuth callback requires a registered, stable redirect URI, and Bolt's WebContainer uses dynamic preview URLs that can't be registered. Deploy to Netlify or Bolt Cloud first, register your deployed URL in Google Cloud Console, and test the complete flow there.
Does the Google Classroom API work with personal Gmail accounts or only Google Workspace for Education?
Basic scopes for reading your own courses and assignments work with any Google account, including personal Gmail. However, scopes that access other users' data (student rosters, all submissions in a course, teacher-level access) require Google Workspace for Education accounts. If you need these scopes with personal accounts, Google's OAuth app verification process is required.
How do I connect Bolt.new to Google Classroom?
Enable the Google Classroom API in Google Cloud Console, create OAuth 2.0 Web Application credentials, configure the redirect URI to your deployed app URL, store the client_id and client_secret in your .env file, and build Next.js API routes for the OAuth authorization and callback flow. The googleapis npm package provides a typed Classroom client for making API calls after authentication.
What data can I read from the Google Classroom API?
With the classroom.courses.readonly scope you can list courses and their details. With classroom.coursework.me.readonly you can read assignments and questions. With classroom.student-submissions.me.readonly you can read submission status for the authenticated user. Teacher-level access to student rosters and all submissions requires Google Workspace for Education accounts and broader scopes that may need OAuth verification.
Is there a Google Classroom API free tier?
The Google Classroom API is free to use with no per-call charges. It's subject to usage quotas: 500 requests per 100 seconds per project and 100 requests per 100 seconds per user. These limits are generous for most applications. If you need higher quotas, you can request increases in Google Cloud Console.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation