Streamlined Linking with OAuth and Sign in with Google (original) (raw)
Overview
OAuth-based Sign in with Google Streamlined linking adds Sign in with Google on top ofOAuth linking. This provides a seamless linking experience for Google users, and it also enables account creation, which allows the user to create a new account on your service using their Google Account.
To perform account linking with OAuth and Sign in with Google, follow these general steps:
- First, ask the user to give consent to access their Google profile.
- Use the information in their profile to check if the user account exists.
- For existing users, link the accounts.
- If you can't find a match for the Google user in your authentication system, validate the ID token received from Google. You can then create a user based on the profile information contained in the ID token.
Account Linking on a user's phone with Streamlined Linking
Figure 1. Account Linking on a user's phone with Streamlined Linking
Streamlined Linking: OAuth + Sign in with Google Flow
The following sequence diagram details interactions between the User, Google, and your token exchange endpoint for Streamlined Linking.
User Google App / Server Your Token Exchange Endpoint Your API 1. User initiates linking 2. Request Sign in with Google 3. Sign in with Google 4. check intent (JWT Assertion) 5. account_found: true/false If account found: 6. get intent If no account: 6. create intent 7. access_token, refresh_token 8. Store user tokens 9. Access user resources
Figure 2. The sequence of events in the Streamlined Linking flow.
Roles and responsibilities
The following table defines the roles and responsibilities of the actors in the Streamlined Linking flow.
| Actor / Component | GAL Role | Responsibilities |
|---|---|---|
| Google App / Server | OAuth Client | Obtains user consent for Sign in with Google, passes identity assertions (JWT) to your server, and securely stores the resulting tokens. |
| Your Token Exchange Endpoint | Identity Provider / Authorization Server | Validates identity assertions, checks for existing accounts, handles the account linking intents (check, get,create), and issues tokens based on the requested intents. |
| Your Service API | Resource Server | Provides access to user data when presented with a valid access token. |
Requirements for Streamlined Linking
- Implement the basic web OAuth linking flow. Your service must support OAuth 2.0-compliant_authorization_ and token exchange endpoints.
- Your token exchange endpoint must support JSON Web Token (JWT) assertions and implement the check, create, and get intents.
- Register your Google API Client ID.
Implement your OAuth server
Your token exchange endpoint must support the check, create, get intents. Follow these steps to complete the account linking flow and to learn when the different intents are used:
- Does the user have an account in your authentication system? (User decides by selecting YES or NO)
- YES : Does the user use the email associated with their Google Account to sign into your platform? (User decides by selecting YES or NO)
- YES : Does the user have a matching account in your authentication system? (check intent is called to confirm)
1. YES : get intent is called and the account is linked if get intent returns successfully.
2. NO : Create New Account? (User decides by selecting YES or NO)
1. YES : create intent is called and the account is linked if create intent returns successfully.
2. NO : The Web OAuth flow is triggered, the user is directed to their browser, and the user is given the option to link with a different email. - NO : The Web OAuth flow is triggered, the user is directed to their browser, and the user is given the option to link with a different email.
- YES : Does the user have a matching account in your authentication system? (check intent is called to confirm)
- NO : Does the user have a matching account in your authentication system? (check intent is called to confirm)
- YES : get intent is called and the account is linked if get intent returns successfully.
- NO : create intent is called and the account is linked if create intent returns successfully.
- YES : Does the user use the email associated with their Google Account to sign into your platform? (User decides by selecting YES or NO)
Check for an existing user account (check intent)
After the user gives consent to access their Google profile, Google sends a request that contains a signed assertion of the Google user's identity. The assertion contains information that includes the user's Google Account ID, name, and email address. The token exchange endpoint configured for your project handles that request.
If the corresponding Google account is already present in your authentication system, your token exchange endpoint responds with account_found=true. If the Google account doesn't match an existing user, your token exchange endpoint returns an HTTP 404 Not Found error with account_found=false.
The request has the following form:
POST /token HTTP/1.1 Host: oauth2.example.com Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&intent=check&assertion=JWT&scope=SCOPES&client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET
Your token exchange endpoint must be able to handle the following parameters:
| Token endpoint parameters | |
|---|---|
| intent | For these requests, the value of this parameter ischeck. |
| grant_type | The type of token being exchanged. For these requests, this parameter has the value urn:ietf:params:oauth:grant-type:jwt-bearer. |
| assertion | A JSON Web Token (JWT) that provides a signed assertion of the Google user's identity. The JWT contains information that includes the user's Google Account ID, name, and email address. |
| client_id | The client ID you assigned to Google. |
| client_secret | The client secret you assigned to Google. |
To respond to the check intent requests, your token exchange endpoint must perform the following steps:
- Validate and decode the JWT assertion.
- Check if the Google account is already present in your authentication system.
Validate and decode the JWT assertion
You can validate and decode the JWT assertion by using aJWT-decoding library for your language. Use Google's public keys, available inJWK orPEM formats, to verify the token's signature.
When decoded, the JWT assertion looks like the following example:
{ "sub": "1234567890", // The unique ID of the user's Google Account "iss": "https://accounts.google.com", // The assertion's issuer "aud": "123-abc.apps.googleusercontent.com", // Your server's client ID "iat": 233366400, // Unix timestamp of the assertion's creation time "exp": 233370000, // Unix timestamp of the assertion's expiration time "name": "Jan Jansen", "given_name": "Jan", "family_name": "Jansen", "email": "jan@gmail.com", // If present, the user's email address "email_verified": true, // true, if Google has verified the email address "hd": "example.com", // If present, the host domain of the user's GSuite email address // If present, a URL to user's profile picture "picture": "https://lh3.googleusercontent.com/a-/AOh14GjlTnZKHAeb94A-FmEbwZv7uJD986VOF1mJGb2YYQ", "locale": "en_US" // User's locale, from browser or phone settings }
In addition to verifying the token's signature, verify that the assertion's issuer (iss field) is https://accounts.google.com, that the audience (aud field) is your assigned client ID, and that the token has not expired (exp field).
Using the email, email_verified and hd fields you can determine if Google hosts and is authoritative for an email address. In cases where Google is authoritative the user is currently known to be the legitimate account owner and you may skip password or other challenges methods. Otherwise, these methods can be used to verify the account prior to linking.
Cases where Google is authoritative:
emailhas a@gmail.comsuffix, this is a Gmail account.email_verifiedis true andhdis set, this is a G Suite account.
Users may register for Google Accounts without using Gmail or G Suite. Whenemail does not contain a @gmail.com suffix and hd is absent Google is not authoritative and password or other challenge methods are recommended to verify the user. email_verified can also be true as Google initially verified the user when the Google account was created, however ownership of the third party email account may have since changed.
Check if the Google account is already present in your authentication system
Check whether either of the following conditions are true:
- The Google Account ID, found in the assertion's
subfield, is in your user database. - The email address in the assertion matches a user in your user database.
If either condition is true, the user has already signed up. In that case, return a response like the following:
HTTP/1.1 200 Success Content-Type: application/json;charset=UTF-8
{ "account_found":"true", }
If neither the Google Account ID nor the email address specified in the assertion matches a user in your database, the user hasn't signed up yet. In this case, your token exchange endpoint needs to reply with a HTTP 404 error that specifies "account_found": "false", as in the following example:
HTTP/1.1 404 Not found Content-Type: application/json;charset=UTF-8
{ "account_found":"false", }
Handle automatic linking (get intent)
After the user gives consent to access their Google profile, Google sends a request that contains a signed assertion of the Google user's identity. The assertion contains information that includes the user's Google Account ID, name, and email address. The token exchange endpoint configured for your project handles that request.
If the corresponding Google Account is already present in your authentication system, your token exchange endpoint returns a token for the user. If the Google Account doesn't match an existing user, your token exchange endpoint returns a linking_error error and optional login_hint.
The request has the following form:
POST /token HTTP/1.1 Host: oauth2.example.com Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&intent=get&assertion=JWT&scope=SCOPES&client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET
Your token exchange endpoint must be able to handle the following parameters:
| Token endpoint parameters | |
|---|---|
| intent | For these requests, the value of this parameter is get. |
| grant_type | The type of token being exchanged. For these requests, this parameter has the value urn:ietf:params:oauth:grant-type:jwt-bearer. |
| assertion | A JSON Web Token (JWT) that provides a signed assertion of the Google user's identity. The JWT contains information that includes the user's Google Account ID, name, and email address. |
| scope | Optional: Any scopes that you've configured Google to request from users. |
| client_id | The client ID you assigned to Google. |
| client_secret | The client secret you assigned to Google. |
To respond to the get intent requests, your token exchange endpoint must perform the following steps:
- Validate and decode the JWT assertion.
- Check if the Google account is already present in your authentication system.
Validate and decode the JWT assertion
You can validate and decode the JWT assertion by using aJWT-decoding library for your language. Use Google's public keys, available inJWK orPEM formats, to verify the token's signature.
When decoded, the JWT assertion looks like the following example:
{ "sub": "1234567890", // The unique ID of the user's Google Account "iss": "https://accounts.google.com", // The assertion's issuer "aud": "123-abc.apps.googleusercontent.com", // Your server's client ID "iat": 233366400, // Unix timestamp of the assertion's creation time "exp": 233370000, // Unix timestamp of the assertion's expiration time "name": "Jan Jansen", "given_name": "Jan", "family_name": "Jansen", "email": "jan@gmail.com", // If present, the user's email address "email_verified": true, // true, if Google has verified the email address "hd": "example.com", // If present, the host domain of the user's GSuite email address // If present, a URL to user's profile picture "picture": "https://lh3.googleusercontent.com/a-/AOh14GjlTnZKHAeb94A-FmEbwZv7uJD986VOF1mJGb2YYQ", "locale": "en_US" // User's locale, from browser or phone settings }
In addition to verifying the token's signature, verify that the assertion's issuer (iss field) is https://accounts.google.com, that the audience (aud field) is your assigned client ID, and that the token has not expired (exp field).
Using the email, email_verified and hd fields you can determine if Google hosts and is authoritative for an email address. In cases where Google is authoritative the user is currently known to be the legitimate account owner and you may skip password or other challenges methods. Otherwise, these methods can be used to verify the account prior to linking.
Cases where Google is authoritative:
emailhas a@gmail.comsuffix, this is a Gmail account.email_verifiedis true andhdis set, this is a G Suite account.
Users may register for Google Accounts without using Gmail or G Suite. Whenemail does not contain a @gmail.com suffix and hd is absent Google is not authoritative and password or other challenge methods are recommended to verify the user. email_verified can also be true as Google initially verified the user when the Google account was created, however ownership of the third party email account may have since changed.
Check if the Google account is already present in your authentication system
Check whether either of the following conditions are true:
- The Google Account ID, found in the assertion's
subfield, is in your user database. - The email address in the assertion matches a user in your user database.
If an account is found for the user, issue an access token and return the values in a JSON object in the body of your HTTPS response, like in the following example:
{ "token_type": "Bearer", "access_token": "ACCESS_TOKEN", "refresh_token": "REFRESH_TOKEN", "expires_in": SECONDS_TO_EXPIRATION }
In some cases, account linking based on ID token might fail for the user. If it does so for any reason, your token exchange endpoint needs to reply with a HTTP 401 error that specifies error=linking_error, as the following example shows:
HTTP/1.1 401 Unauthorized Content-Type: application/json;charset=UTF-8
{ "error":"linking_error", "login_hint":"foo@bar.com" }
When Google receives a 401 error response with linking_error, Google sends the user to your authorization endpoint with login_hint as a parameter. The user completes account linking using the OAuth linking flow in their browser.
Handle account creation using Sign in with Google (create intent)
When a user needs to create an account on your service, Google makes a request to your token exchange endpoint that specifies intent=create.
The request has the following form:
POST /token HTTP/1.1 Host: oauth2.example.com Content-Type: application/x-www-form-urlencoded
response_type=token&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&scope=SCOPES&intent=create&assertion=JWT&client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET
Your token exchange endpoint must able to handle the following parameters:
| Token endpoint parameters | |
|---|---|
| intent | For these requests, the value of this parameter is create. |
| grant_type | The type of token being exchanged. For these requests, this parameter has the value urn:ietf:params:oauth:grant-type:jwt-bearer. |
| assertion | A JSON Web Token (JWT) that provides a signed assertion of the Google user's identity. The JWT contains information that includes the user's Google Account ID, name, and email address. |
| client_id | The client ID you assigned to Google. |
| client_secret | The client secret you assigned to Google. |
The JWT within the assertion parameter contains the user's Google Account ID, name, and email address, which you can use to create a new account on your service.
To respond to the create intent requests, your token exchange endpoint must perform the following steps:
- Validate and decode the JWT assertion.
- Validate user information and create new account.
Validate and decode the JWT assertion
You can validate and decode the JWT assertion by using aJWT-decoding library for your language. Use Google's public keys, available inJWK orPEM formats, to verify the token's signature.
When decoded, the JWT assertion looks like the following example:
{ "sub": "1234567890", // The unique ID of the user's Google Account "iss": "https://accounts.google.com", // The assertion's issuer "aud": "123-abc.apps.googleusercontent.com", // Your server's client ID "iat": 233366400, // Unix timestamp of the assertion's creation time "exp": 233370000, // Unix timestamp of the assertion's expiration time "name": "Jan Jansen", "given_name": "Jan", "family_name": "Jansen", "email": "jan@gmail.com", // If present, the user's email address "email_verified": true, // true, if Google has verified the email address "hd": "example.com", // If present, the host domain of the user's GSuite email address // If present, a URL to user's profile picture "picture": "https://lh3.googleusercontent.com/a-/AOh14GjlTnZKHAeb94A-FmEbwZv7uJD986VOF1mJGb2YYQ", "locale": "en_US" // User's locale, from browser or phone settings }
In addition to verifying the token's signature, verify that the assertion's issuer (iss field) is https://accounts.google.com, that the audience (aud field) is your assigned client ID, and that the token has not expired (exp field).
Using the email, email_verified and hd fields you can determine if Google hosts and is authoritative for an email address. In cases where Google is authoritative the user is currently known to be the legitimate account owner and you may skip password or other challenges methods. Otherwise, these methods can be used to verify the account prior to linking.
Cases where Google is authoritative:
emailhas a@gmail.comsuffix, this is a Gmail account.email_verifiedis true andhdis set, this is a G Suite account.
Users may register for Google Accounts without using Gmail or G Suite. Whenemail does not contain a @gmail.com suffix and hd is absent Google is not authoritative and password or other challenge methods are recommended to verify the user. email_verified can also be true as Google initially verified the user when the Google account was created, however ownership of the third party email account may have since changed.
Validate user information and create new account
Check whether either of the following conditions are true:
- The Google Account ID, found in the assertion's
subfield, is in your user database. - The email address in the assertion matches a user in your user database.
If either condition is true, prompt the user to link their existing account with their Google Account. To do so, respond to the request with an HTTP 401 error that specifies error=linking_error and gives the user's email address as thelogin_hint. The following is a sample response:
HTTP/1.1 401 Unauthorized Content-Type: application/json;charset=UTF-8
{ "error":"linking_error", "login_hint":"foo@bar.com" }
When Google receives a 401 error response with linking_error, Google sends the user to your authorization endpoint with login_hint as a parameter. The user completes account linking using the OAuth linking flow in their browser.
If neither condition is true, create a new user account with the information provided in the JWT. New accounts don't typically have a password set. It's recommended that you add Sign in with Google to other platforms to enable users to sign in with Google across the surfaces of your application. Alternatively, you can email the user a link that starts your password recovery flow to allow the user to set a password to sign in on other platforms.
When the creation is completed, issue an access token and return the values in a JSON object in the body of your HTTPS response, like in the following example:
{ "token_type": "Bearer", "access_token": "ACCESS_TOKEN", "refresh_token": "REFRESH_TOKEN", "expires_in": SECONDS_TO_EXPIRATION }
Get your Google API Client ID
You will be required to provide your Google API Client ID during the Account Linking registration process. To get your API Client ID using the project you created while completing theOAuth Linking steps. To do so, complete the following steps:
- Go to the Clients page.
- Create or select a Google APIs project.
If your project doesn't have a Client ID for the Web application Type, clickCreate Client to create one. Be sure to include your site's domain in the Authorized JavaScript origins box. When you perform local tests or development, you must add bothhttp://localhostandhttp://localhost:<port_number>to the Authorized JavaScript originsfield.
Validate your implementation
You can validate your implementation by using theOAuth 2.0 Playground tool.
In the tool, do the following steps:
- Click Configurationto open the OAuth 2.0 Configuration window.
- In the OAuth flow field, select Client-side.
- In the OAuth Endpoints field, select Custom.
- Specify your OAuth 2.0 endpoint and the client ID you assigned to Google in the corresponding fields.
- In the Step 1 section, don't select any Google scopes. Instead, leave this field blank or type a scope valid for your server (or an arbitrary string if you don't use OAuth scopes). When you're done, click Authorize APIs.
- In the Step 2 and Step 3 sections, go through the OAuth 2.0 flow and verify that each step works as intended.
You can validate your implementation by using theGoogle Account Linking Demo tool.
In the tool, do the following steps:
- Click the Sign in with Google button.
- Choose the account you'd like to link.
- Enter the service ID.
- Optionally enter one or more scopes that you will request access for.
- Click Start Demo.
- When prompted, confirm that you may consent and deny the linking request.
- Confirm that you are redirected to your platform.