<@U04UQ68083H> Account linking with Google is only...
# ory-copilot
r
@chilly-king-10285 Account linking with Google is only working for emails ending in "gmail.com". If I try sign in with Google using a Google workspace domain like "mycompany.com" I get redirected to the registration flow instead of the link flow. But if I use a "gmail.com" email then the linking works as expected.
c
A message from kapa.ai
In Ory, you can use the
hd
claim for Google, which is the hosted Google Workspace domain of the user. This claim is used only when the user has a Google Workspace account. If you want to use this data mapping, you must include the
first_name
and
last_name
fields in your Identity Schema. Here is a sample Jsonnet code snippet that maps the desired claims to the Ory Identity schema:
Copy code
jsonnet local claims = {     email_verified: false,   } + std.extVar('claims');      {     identity: {       traits: {         [if 'email' in claims && claims.email_verified then 'email' else null]: claims.email,         first_name: claims.given_name,         last_name: claims.family_name,         [if 'hd' in claims && claims.email_verified then 'hd' else null]: claims.hd,       },     },   }
You can then encode the Jsonnet snippet with Base64 or host it under a URL accessible to Ory Network. If you're still encountering issues, it might be due to common problems such as Redirect URI mismatch, Redirect loops during registration, or Domain verification issues. You can refer to the [Social sign-in troubleshooting](https://www.ory.sh/docs/troubleshooting/troubleshooting-social-sign-in) guide for more information. Sources: - [Data Mapping](https://www.ory.sh/docs/kratos/social-signin/google#data-mapping) - [Troubleshooting](https://www.ory.sh/docs/kratos/social-signin/dingtalk#troubleshooting)
r
@chilly-king-10285 Here is our identity schema:
Copy code
{
  "$id": "<https://schemas.ory.sh/presets/kratos/identity.email.schema.json>",
  "title": "Person",
  "type": "object",
  "properties": {
    "traits": {
      "type": "object",
      "properties": {
        "first_name": {
          "type": "string",
          "title": "First Name",
          "maxLength": 256
        },
        "last_name": {
          "type": "string",
          "title": "Last Name",
          "maxLength": 256
        },
        "email": {
          "type": "string",
          "format": "email",
          "title": "E-Mail",
          "<http://ory.sh/kratos|ory.sh/kratos>": {
            "credentials": {
              "password": {
                "identifier": true
              },
              "webauthn": {
                "identifier": true
              },
              "totp": {
                "account_name": true
              },
              "code": {
                "identifier": true,
                "via": "email"
              }
            },
            "recovery": {
              "via": "email"
            },
            "verification": {
              "via": "email"
            }
          },
          "maxLength": 320
        },
        "linkStrategy": {
          "const": "auto"
        }
      },
      "required": [
        "email"
      ],
      "additionalProperties": false
    }
  }
}
and our data mapping for Google sign in:
Copy code
local claims = {
  email_verified: true,
} + std.extVar('claims');

{
  identity: {
    traits: {
      [if 'email' in claims && claims.email_verified then 'email' else null]: claims.email,
      first_name: claims.given_name,
      last_name: claims.family_name,
      [if 'hd' in claims && claims.email_verified then 'hd' else null]: claims.hd,
    },
  },
}
c
A message from kapa.ai
Your identity schema and data mapping for Google sign-in look correct. In your identity schema, you have defined
first_name
,
last_name
, and
email
as properties. These are also the fields you are mapping in your Jsonnet code snippet for Google sign-in. Here's the Jsonnet code snippet:
Copy code
jsonnet local claims = {   email_verified: true, } + std.extVar('claims');  {   identity: {     traits: {       [if 'email' in claims && claims.email_verified then 'email' else null]: claims.email,       first_name: claims.given_name,       last_name: claims.family_name,       [if 'hd' in claims && claims.email_verified then 'hd' else null]: claims.hd,     },   }, }
In this snippet, you are mapping the
email
,
given_name
, and
family_name
claims from Google to the
email
,
first_name
, and
last_name
traits in your identity schema, respectively. The
hd
claim, which represents the hosted Google Workspace domain of the user, is also being mapped. Remember, for Google, you can use the
hd
claim which is the hosted Google Workspace domain of the user. This claim is used only when the user has a Google Workspace account. Sources: - [Data Mapping](https://www.ory.sh/docs/kratos/social-signin/google#data-mapping) - [Additional Configuration](https://www.ory.sh/docs/kratos/social-signin/google#additional-configuration)
r
@chilly-king-10285 I don't understand what you mean by:
Remember, for Google, you can use the
hd
claim which is the hosted Google Workspace domain of the user. This claim is used only when the user has a Google Workspace account.
c
A message from kapa.ai
The
hd
claim is a parameter that you can use when setting up Google as a social sign-in provider in Ory. This parameter represents the hosted Google Workspace domain of the user. In other words, if a user is part of a Google Workspace (formerly known as G Suite), their account is associated with a specific domain (like
<http://mycompany.com|mycompany.com>
). This domain is what the
hd
claim represents. This claim is only used when the user has a Google Workspace account. If the user is signing in with a regular Google account (like
<mailto:user@gmail.com|user@gmail.com>
), the
hd
claim would not be applicable. In your Jsonnet code snippet, you're checking if the
hd
claim exists in the claims and if the email is verified. If both conditions are true, you're mapping the
hd
claim to the
hd
trait in your identity schema. Here's the relevant part of your Jsonnet code snippet:
Copy code
jsonnet [if 'hd' in claims && claims.email_verified then 'hd' else null]: claims.hd,
This means that if a user signs in with a Google Workspace account, their domain information would be included in their identity traits in Ory. Sources: - [Data Mapping](https://www.ory.sh/docs/kratos/social-signin/google#data-mapping) - [Additional Configuration](https://www.ory.sh/docs/kratos/social-signin/google#additional-configuration)
r
@chilly-king-10285 So if the hd claim is set and the email is verified in google workspaces then I should be able to link the "mycompany.com" google account to the one that I setup using email and password earlier?
c
A message from kapa.ai
Yes, that's correct. If the
hd
claim is set and the email is verified in Google Workspaces, you should be able to link the
<http://mycompany.com|mycompany.com>
Google account to the one that you set up using email and password earlier. The
hd
claim represents the hosted Google Workspace domain of the user. This claim is used only when the user has a Google Workspace account. In your Jsonnet code snippet, you're checking if the
hd
claim exists in the claims and if the email is verified. If both conditions are true, you're mapping the
hd
claim to the
hd
trait in your identity schema. Here's the relevant part of your Jsonnet code snippet:
Copy code
jsonnet [if 'hd' in claims && claims.email_verified then 'hd' else null]: claims.hd,
This means that if a user signs in with a Google Workspace account, their domain information would be included in their identity traits in Ory. However, please note that there are no expected validation errors except for an error where the profile (for example Google) to be linked is already linked with another identity in the system. If you encounter this error, you will need to unlink the profile from the other identity before you can link it to the new one. Sources: - [Data Mapping](https://www.ory.sh/docs/kratos/social-signin/google#data-mapping) - [Additional Configuration](https://www.ory.sh/docs/kratos/social-signin/google#additional-configuration) - [Un-/linking from/with Google](https://www.ory.sh/docs/kratos/self-service/flows/user-settings#un-linking-fromwith-google-facebook-github--openid-connect--oauth-20)
r
@chilly-king-10285 so if this isn't working then does that mean either the hd property isn't present or my email isn't verified in google workspace?
c
A message from kapa.ai
Yes, if the account linking isn't working, it could be due to either the
hd
property not being present or the email not being verified in Google Workspace. In your Jsonnet code snippet, you're checking if the
hd
claim exists in the claims and if the email is verified. If both conditions are true, you're mapping the
hd
claim to the
hd
trait in your identity schema. Here's the relevant part of your Jsonnet code snippet:
Copy code
jsonnet [if 'hd' in claims && claims.email_verified then 'hd' else null]: claims.hd,
If the
hd
claim is not present or the email is not verified, the
hd
trait will not be set in the identity schema, which could prevent the account linking from working correctly. Sources: - [Data Mapping](https://www.ory.sh/docs/kratos/social-signin/google#data-mapping) - [Additional Configuration](https://www.ory.sh/docs/kratos/social-signin/google#additional-configuration)
r
@chilly-king-10285 Does this part of the data mapping:
Copy code
local claims = {
  email_verified: true,
} + std.extVar('claims');
mean that email_verified would always be true then since it is set to true?
c
A message from kapa.ai
No, the
email_verified: true
in the code snippet does not mean that
email_verified
would always be true. This is just the initial value set for
email_verified
in the
claims
object. Here's the relevant part of your Jsonnet code snippet:
Copy code
jsonnet local claims = {   email_verified: true, } + std.extVar('claims');
In this code,
std.extVar('claims')
is used to extend the
claims
object with the actual claims returned by the identity provider (in this case, Google). If the identity provider returns an
email_verified
claim, it will overwrite the initial
email_verified: true
value. So, the actual value of
email_verified
in the
claims
object will depend on the claims returned by the identity provider. Sources: - [Data Mapping](https://www.ory.sh/docs/kratos/social-signin/google#data-mapping) - [Additional Configuration](https://www.ory.sh/docs/kratos/social-signin/google#additional-configuration)
r
@chilly-king-10285 if I updated the data mapping to this instead:
Copy code
local claims = {
  email_verified: true,
} + std.extVar('claims');

{
  identity: {
    traits: {
      [if 'email' in claims then 'email' else null]: claims.email,
      first_name: claims.given_name,
      last_name: claims.family_name,
      [if 'hd' in claims then 'hd' else null]: claims.hd,
    },
  },
}
Then it wouldn't care about email verification on Google Workspace's side? Obviously I shouldn't leave it like this but I wanted to test it. I made this change and tried logging in with a custom domain google account but I get taken to the register flow still. Does this mean that the hd part of the claim isn't coming through somehow?
c
A message from kapa.ai
Yes, you're correct. By removing the
&& claims.email_verified
condition from your Jsonnet code snippet, you're no longer checking whether the email is verified by Google Workspace. Here's the updated part of your Jsonnet code snippet:
Copy code
jsonnet [if 'email' in claims then 'email' else null]: claims.email, [if 'hd' in claims then 'hd' else null]: claims.hd,
In this updated code, you're only checking if the
email
and
hd
claims exist in the claims returned by the identity provider. If they exist, you're mapping them to the
email
and
hd
traits in your identity schema, respectively. If you're still being taken to the register flow after making this change, it could mean that the
hd
claim is not being returned by Google Workspace. This could happen if the user is not part of a Google Workspace or if the
hd
claim is not included in the scopes requested from Google Workspace. Remember, it's important to ensure that email addresses are verified to prevent several attack vectors related to social sign in. So, you should add the email verification check back once you're done testing. Sources: - [Data Mapping](https://www.ory.sh/docs/kratos/social-signin/google#data-mapping) - [Additional Configuration](https://www.ory.sh/docs/kratos/social-signin/google#additional-configuration) - [Emails and Phone Numbers](https://www.ory.sh/docs/kratos/social-signin/data-mapping#emails-and-phone-numbers)
r
@chilly-king-10285 how do I verify "This could happen if the user is not part of a Google Workspace or if the
hd
claim is not included in the scopes requested from Google Workspace."
c
A message from kapa.ai
To verify if a user is part of a Google Workspace, you can check the user's email domain. If the email domain is a custom domain (like
<mailto:user@mycompany.com|user@mycompany.com>
), the user is likely part of a Google Workspace. If the email domain is
<http://gmail.com|gmail.com>
, the user is not part of a Google Workspace. To verify if the
hd
claim is included in the scopes requested from Google Workspace, you can check your OAuth 2.0 scopes. In your Ory configuration, you should have a section that defines the scopes requested from Google. For a basic setup, you would typically request the
email
and
profile
scopes. Here's an example:
Copy code
yaml selfservice:     methods:       oidc:         config:           providers:             - id: google             provider: google               client_id: ....              client_secret: ....              mapper_url: "base64://{YOUR_BASE64_ENCODED_JSONNET_HERE}"               scope:                 - email                 - profile
In this example, the
email
and
profile
scopes are being requested from Google. If the
hd
claim is not being returned, you might need to request additional scopes. You can refer to the [Google OAuth 2.0 Scopes documentation](https://developers.google.com/identity/protocols/oauth2/scopes) to learn more about the scopes available for Google. Sources: - [Additional Configuration](https://www.ory.sh/docs/kratos/social-signin/google#additional-configuration) - [Google OAuth 2.0 Scopes](https://developers.google.com/identity/protocols/oauth2/scopes)
r
@chilly-king-10285 this is my configuration:
Copy code
oidc:
      config:
        base_redirect_uri: ...
        providers:
        - client_id: ...
          client_secret: ...
          id: google
          label: Google
          mapper_url: ...
          provider: google
          scope:
          - email
          - profile
      enabled: true
Seems that hd isn't part of the scope and I think that is the underlying issue. How can I make sure it is?
c
A message from kapa.ai
The
hd
claim in Google OAuth is not something you explicitly request via scopes. It is automatically included if the user is part of a Google Workspace domain. The
hd
claim is included in the ID token if the user is a member of the Google Workspace that you specified as an audience in the request. In your current configuration, you're requesting the
email
and
profile
scopes:
Copy code
yaml scope:   - email   - profile
These scopes allow you to access the user's email address and basic profile information. They do not directly control the
hd
claim. If the
hd
claim is not being returned, it could be because the user is not part of a Google Workspace, or because the Google Workspace domain of the user is not specified as an audience in the request. To specify the Google Workspace domain as an audience, you can use the
hd
parameter in the authorization request. The
hd
parameter limits the login/registration process to a Google Organization, for example
<http://mycollege.edu|mycollege.edu>
. Here's an example of how to include the
hd
parameter in the authorization request:
Copy code
yaml parameters:   hd: <http://mycompany.com|mycompany.com>
Please note that this is just an example. The actual way to include the
hd
parameter in the authorization request might vary depending on your setup. Sources: - [Additional Configuration](https://www.ory.sh/docs/kratos/social-signin/google#additional-configuration) - [Google OAuth 2.0 Scopes](https://developers.google.com/identity/protocols/oauth2/scopes) - [Google OpenID Connect](https://developers.google.com/identity/protocols/oauth2/openid-connect)