Taking it to production
Consent screen, verification, and what breaks on the day you launch.
Open this lesson in the learning hubKey points
- A project in testing mode only allows the test users you list, and refuses everyone else. Moving to production requires publishing the consent screen.
- Requesting sensitive or restricted scopes triggers Google verification, which takes time and may require a security assessment. Basic
openid profile emaildoes not. - Register every redirect URI you actually use - local development, staging and production are three different entries, matched exactly.
- A refresh token is only issued when you request offline access, and typically only on the first consent. Losing it means the user has to re-consent, so store it when you get it.
- Rotate the client secret if it has ever been committed, printed in a log, or shared. Google lets you hold two secrets briefly so rotation need not be an outage.
- Handle the user revoking access from their Google account page: your refresh token stops working, and the correct response is to prompt them to sign in again rather than retrying.
Example
# The console checklist, in order:
#
# 1. OAuth consent screen
# - External unless you are Workspace-only
# - app name, support email, logo, privacy policy and terms URLs
# - authorised domains
# - PUBLISH it, or only listed test users can sign in
#
# 2. Scopes
# openid, profile, email no verification needed
# Gmail, Drive, Calendar SENSITIVE or RESTRICTED
# -> verification, and possibly a
# third-party security assessment
#
# 3. Credentials -> OAuth client ID -> Web application
# Authorised redirect URIs, EXACT, one line per environment:
# http://localhost:8080/login/oauth2/code/google
# https://staging.example.com/login/oauth2/code/google
# https://example.com/login/oauth2/code/google
---
# Refresh token: only with offline access, and usually only ONCE.
spring:
security:
oauth2:
client:
provider:
google:
authorization-uri: >-
https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&prompt=consent
# access_type=offline -> issue a refresh token
# prompt=consent -> force re-consent, so you get one again
#
# Without prompt=consent, a returning user consents silently and NO
# refresh token is issued - which is why it works in development
# (first consent) and fails in production (returning users).
---
# THE FAILURES YOU WILL ACTUALLY HIT:
#
# redirect_uri_mismatch the URI is not registered EXACTLY.
# Behind a proxy? set forward-headers-strategy.
# access_blocked consent screen is unpublished, or the scope
# needs verification
# invalid_grant refresh token revoked or expired ->
# prompt a fresh sign-in, do not retry
# no refresh_token missing access_type=offline, or a returning
# user consented silently
Publish the consent screen, register every redirect URI exactly, and request offline access or you will never get a refresh token.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the OAuth with Google course, and every lesson in it is listed on the OAuth with Google contents page.