Unable to get the refresh_token from Google via Azure AD B2C

SamD 151 Reputation points
2020-09-25T07:46:04.933+00:00

We use Azure AD B2C as the IDP. And in AAD B2C, we have enabled Google as an external IDP. When users login using their Google accounts, our application expect access_token and refresh_token from Google.

In order to get a refresh_token from Google, we should pass a parameter called access_type with the value offline (Reference: https://developers.google.com/identity/protocols/oauth2/web-server#httprest_1).

So, I configured custom policies as shown below (in TrustFrameworkExtensions.xml)

Configured new claims:

<ClaimsSchema>
  <ClaimType Id="third_party_idp_access_token">
    <DisplayName>Access token from third party IDP</DisplayName>
    <DataType>string</DataType>
    <DefaultPartnerClaimTypes>
      <Protocol Name="OAuth2" PartnerClaimType="{oauth2:access_token}" />
      <Protocol Name="OpenIdConnect" PartnerClaimType="{oauth2:access_token}" />
    </DefaultPartnerClaimTypes>
    <UserHelpText>access token form 3rd party IDP</UserHelpText>
  </ClaimType>
  <ClaimType Id="third_party_idp_refresh_token">
    <DisplayName>Refresh token from third party IDP</DisplayName>
    <DataType>string</DataType>
    <DefaultPartnerClaimTypes>
      <Protocol Name="OAuth2" PartnerClaimType="{oauth2:refresh_token}" />
      <Protocol Name="OpenIdConnect" PartnerClaimType="{oauth2:refresh_token}" />
    </DefaultPartnerClaimTypes>
    <UserHelpText>refresh token form 3rd party IDP.</UserHelpText>
  </ClaimType>

  <ClaimType Id="google_access_type">
    <DisplayName>access_type</DisplayName>
    <DataType>string</DataType>
    <DefaultPartnerClaimTypes>
      <Protocol Name="OAuth2" PartnerClaimType="access_type" />
      <Protocol Name="OpenIdConnect" PartnerClaimType="access_type" />
    </DefaultPartnerClaimTypes>        
    <UserHelpText>Special parameter passed for google OAuth2 to get refresh_token</UserHelpText>
  </ClaimType>
</ClaimsSchema>

Configured ClaimsProvider:

<ClaimsProvider>
  <Domain>google.com</Domain>
  <DisplayName>Google</DisplayName>
  <TechnicalProfiles>
    <TechnicalProfile Id="Google-OAUTH">
      <DisplayName>Google</DisplayName>
      <Protocol Name="OAuth2" />
      <Metadata>
        <Item Key="ProviderName">google</Item>
        <Item Key="authorization_endpoint">https://accounts.google.com/o/oauth2/v2/auth</Item>
        <Item Key="AccessTokenEndpoint">https://oauth2.googleapis.com/token</Item>
        <Item Key="ClaimsEndpoint">https://www.googleapis.com/oauth2/v2/userinfo</Item>
        <Item Key="scope">email profile</Item>
        <Item Key="HttpBinding">POST</Item>
        <Item Key="UsePolicyInRedirectUri">0</Item>
        <Item Key="client_id">xxxxxxxx.apps.googleusercontent.com</Item>
      </Metadata>
      <CryptographicKeys>
        <Key Id="client_secret" StorageReferenceId="B2C_1A_GoogleSecret" />
      </CryptographicKeys>
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="google_access_type" DefaultValue="offline"/>
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="id" />
        <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
        <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />
        <OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="family_name" />
        <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
        <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="google.com" />
        <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication" />
        <OutputClaim ClaimTypeReferenceId="third_party_idp_access_token" PartnerClaimType="{oauth2:access_token}" DefaultValue="access-token-empty" />
        <OutputClaim ClaimTypeReferenceId="third_party_idp_refresh_token" PartnerClaimType="{oauth2:refresh_token}" DefaultValue="refresh-token-empty" />
      </OutputClaims>
      <OutputClaimsTransformations>
        <OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" />
        <OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" />
        <OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" />
        <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromAlternativeSecurityId" />
      </OutputClaimsTransformations>
      <UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin" />
    </TechnicalProfile>
  </TechnicalProfiles>
</ClaimsProvider>

Then added Google to the User Journey.

Our application use OIDC authorization code flow, to authenticate user with AAD B2C. After the authentication, application receives Google access_token. But refresh_token is not being passed through properly.
(The value of the refresh_token, which application get is: “refresh-token-empty” - that is the default value I have configured in CustomPolicies).

During the Authentication flow I can see that access_type is properly set as offline.

On a different note:
I tried to get the refresh_token directly from Google (without AAD B2C) via postman and it works fine. In that case Google token endpoint returns something like this:

{
  "access_token": "xxxxxxxx",
  "expires_in": 3599,
  "refresh_token": " xxxxxxxx ",
  "scope": "openid https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile",
  "token_type": "Bearer",
  "id_token": " xxxxxxxx "
}

Any idea why we can not retrieve Google refresh token via AAD B2C ?

Microsoft Entra External ID
Microsoft Entra External ID
A modern identity solution for securing access to customer, citizen and partner-facing apps and services. It is the converged platform of Azure AD External Identities B2B and B2C. Replaces Azure Active Directory External Identities.
2,662 questions
{count} votes

Accepted answer
  1. Jas Suri 91 Reputation points Microsoft Employee
    2020-10-16T09:42:08.113+00:00

    This works for me

            <TechnicalProfile Id="Google-OAUTH">  
              <DisplayName>Google</DisplayName>  
              <Protocol Name="OAuth2" />  
              <Metadata>  
                <Item Key="ProviderName">google</Item>  
                <Item Key="authorization_endpoint">https://accounts.google.com/o/oauth2/v2/auth</Item>  
                <Item Key="AccessTokenEndpoint">https://oauth2.googleapis.com/token</Item>  
                <Item Key="ClaimsEndpoint">https://www.googleapis.com/oauth2/v1/userinfo</Item>  
                <Item Key="scope">email profile https://www.googleapis.com/auth/drive.metadata.readonly</Item>  
                <Item Key="HttpBinding">POST</Item>  
                <Item Key="UsePolicyInRedirectUri">0</Item>  
                <Item Key="client_id">835075501086-brcgj84n78ukp5ob2mnoa220q9p9rlns.apps.googleusercontent.com</Item>  
              </Metadata>  
              <CryptographicKeys>  
                <Key Id="client_secret" StorageReferenceId="B2C_1A_GoogleSecret" />  
              </CryptographicKeys>  
              <InputClaims>  
                <InputClaim ClaimTypeReferenceId="access_type" PartnerClaimType="access_type" DefaultValue="offline" />  
              </InputClaims>  
              <OutputClaims>  
                <OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="id" />  
                <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />  
                <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />  
                <OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="family_name" />  
                <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />  
                <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="google.com" />  
                <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication" />  
                <OutputClaim ClaimTypeReferenceId="ms_access_token" PartnerClaimType="{oauth2:access_token}"/>  
                <OutputClaim ClaimTypeReferenceId="ms_refresh_token" PartnerClaimType="{oauth2:refresh_token}" DefaultValue="none"/>  
              </OutputClaims>  
              <OutputClaimsTransformations>  
                <OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" />  
                <OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" />  
                <OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" />  
                <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromAlternativeSecurityId" />  
              </OutputClaimsTransformations>  
              <UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin" />  
            </TechnicalProfile>  
    

    32873-image.png


0 additional answers

Sort by: Most helpful