Skip to main content

Social Authentication

info
What you'll learn
  • How to authenticate with Auth0 for Tenant with cy.origin()
  • How to use cy.session() to cache authenticated users
caution

Not recommended in CI

Cypress does not recommend testing social connection authentication as a primary means of authentication testing. This is due to the challenges mentioned in our Best Practices Guide.

Relying on social authentication in CI will likely result in bot detection and in some cases, account suspension due to violating the provider's Terms of Service.

Application Setup

For this guide, we're going to set up an application that uses Auth0 for Tenant that has social connections set up for Google, Facebook, and Microsoft which will authenticate users on our behalf to our application.

Set up the Auth0 tenant

To get started, first create a free Auth0 account and select the I am a new Auth0 User flow. This will have 4 steps:

  • Step 1: When configuring your Sample App, please select the Single-Page App for you platform and React for the technology.
  • Step 2: For Social Connections, please select Facebook, Microsoft, and Google
  • Step 3: Try login and verify the connections are set up properly
  • Step 4: You can either download the sample via the Download Sample App button or clone it here. We'll need this application in the next step. Select I am Ready to Use Auth0. Your social connections on your Auth0 tenant should now be configured correctly

Set up the application

On your Auth0 dashboard, visit Applications Dropdown in the left menu. Select the dropdown and go to Applications.

  • Select the Default Application
  • Visit the Settings tab
    • Copy the domain and client ID fields inside Basic Information. These will be needed shortly.
    • The Application Properties should have Single Page Application selected for Application Type,
    • Inside Application URIs, please add http://localhost:3000 to Allowed Callback URLs, Allowed Web Origins and Allowed Logout URLs.
  • Create the src/auth_config.json file from the src/auth_config.json.example file as described in the sample app.
  • Once created, paste the domain and client ID into their respective fields inside src/auth_config.json. The audience key can be removed. The login/callback URIs will default to http://localhost:3000 which is the url of our test application.
  • Install the application dependencies and start the dev server
  • Verify the application is running correctly by visiting http://localhost:3000 and clicking the Log in button in the top right corner. Select one of our social connections and log in and make sure to complete the Authorize App prompt. This only needs to be done once. This should take you back to the sample app authenticated as the test user. When finished, click the Log Out dropdown button. Repeat for Google, Microsoft, and Facebook or the accounts you would like to test.

Here is what this process should look like for Facebook setup:

Test with Cypress

Now that our application is set up and ready to go, we're ready to write our automated tests.

caution

For these social connections, the experimentalModifyObstructiveThirdPartyCode configuration option must be enabled.

Setting Auth0 app credentials in Cypress

To have access to test user credentials within our tests we need to configure Cypress to use the social username, password, and name environment variables set in the cypress.env.json file or by one of our supported methods.

cypress.env.json
{
"GOOGLE_USERNAME": "",
"GOOGLE_PASSWORD": "",
"GOOGLE_NAME": "",
"MICROSOFT_USERNAME": "",
"MICROSOFT_PASSWORD": "",
"MICROSOFT_NAME": "",
"FACEBOOK_USERNAME": "",
"FACEBOOK_PASSWORD": "",
"FACEBOOK_NAME": ""
}

Login with cy.origin()

We'll write a custom command called loginToAuth0ViaSocial to perform a login to either Facebook, Google, or Microsoft. This command will use cy.origin() to:

  1. Navigate to the Auth0 login
  2. Select the Continue with ... button and sign in with social credentials
  3. Sign in and redirect back to the sample app
  4. Cache the results with cy.session()

For demonstration, we'll have a function for each provider.

Facebook Login Function

cypress/support/commands.ts
import { domain as Auth0Domain } from '../../src/auth_config.json'

function logIntoFacebook(username: string, password: string, name: string) {
cy.visit('http://localhost:3000')
cy.get('#qsLoginBtn').click()

cy.origin(Auth0Domain, () => {
cy.scrollTo('bottom')
cy.get('form[data-provider="facebook"]').submit()
})

cy.origin(
'https://www.facebook.com',
{
args: {
username,
password,
},
},
({ username, password }) => {
cy.get('input#email').type(username)
cy.get('input#pass').type(password, {
log: false,
})
cy.get('[type="submit"]').contains('Log In').click()
}
)

cy.get('h6.dropdown-header').should('contain', name)
}

Google Login Function

cypress/support/commands.ts
import { domain as Auth0Domain } from '../../src/auth_config.json'

function logIntoGoogle(username: string, password: string, name: string) {
Cypress.on(
'uncaught:exception',
(err) =>
!err.message.includes('ResizeObserver loop') &&
!err.message.includes('Error in protected function')
)
cy.visit('http://localhost:3000')
cy.get('#qsLoginBtn').click()

cy.origin(Auth0Domain, () => {
cy.scrollTo('bottom')
cy.get('form[data-provider="google"]').submit()
})

cy.origin(
'https://accounts.google.com',
{
args: {
username,
password,
},
},
({ username, password }) => {
Cypress.on(
'uncaught:exception',
(err) =>
!err.message.includes('ResizeObserver loop') &&
!err.message.includes('Error in protected function')
)

cy.get('input[type="email"]').type(username, {
log: false,
})
// NOTE: The element exists on the original form but is hidden and gets rerendered, which leads to intermittent detached DOM issues
cy.contains('Next').click().wait(4000)
cy.get('[type="password"]').type(password, {
log: false,
})
cy.contains('Next').click().wait(4000)
}
)

cy.get('h6.dropdown-header').should('contain', name)
}

Microsoft Login Function

cypress/support/commands.ts
import { domain as Auth0Domain } from '../../src/auth_config.json'

function logIntoMicrosoft(username: string, password: string, name: string) {
cy.visit('http://localhost:3000')
cy.get('#qsLoginBtn').click()

cy.origin(Auth0Domain, () => {
cy.scrollTo('bottom')
cy.get('form[data-provider="windowslive"]').submit()
})

cy.origin(
'login.live.com',
{
args: {
username,
password,
},
},
({ username, password }) => {
cy.get('input[type="email"]').type(username)
cy.get('input[type="submit"]').click()
cy.get('input[type="password"]').type(password, {
log: false,
})
cy.get('input[type="submit"]').click()
cy.get('#idBtn_Back').click()
}
)

cy.get('h6.dropdown-header').should('contain', name)
}

Combined Login Command

We can wire these functions together in a single command, like so:

cypress/support/commands.ts
Cypress.Commands.add(
'loginToAuth0ViaSocial',
(SOCIAL_PROVIDER: 'microsoft' | 'google' | 'facebook') => {
const log = Cypress.log({
displayName: 'Social LOGIN',
message: [`🔐 Authenticating | ${SOCIAL_PROVIDER}`],
// @ts-ignore
autoEnd: false,
})
log.snapshot('before')

switch (SOCIAL_PROVIDER) {
case 'microsoft':
logIntoMicrosoft(
Cypress.env('MICROSOFT_USERNAME'),
Cypress.env('MICROSOFT_PASSWORD'),
Cypress.env('MICROSOFT_NAME')
)
break
case 'google':
logIntoGoogle(
Cypress.env('GOOGLE_USERNAME'),
Cypress.env('GOOGLE_PASSWORD'),
Cypress.env('GOOGLE_NAME')
)
break
case 'facebook':
logIntoFacebook(
Cypress.env('FACEBOOK_USERNAME'),
Cypress.env('FACEBOOK_PASSWORD'),
Cypress.env('FACEBOOK_NAME')
)
break
default:
throw new Error('no social provider configured!')
}

log.snapshot('after')
log.end()
}
)

Now, we can use our loginToAuth0ViaSocial command in the test. Below is our test to login as a user via Auth0 and run a basic check.

auth.cy.js
describe('Social Logins Demo', () => {
beforeEach(() => {
// can provide facebook, google, or microsoft here
cy.loginToAuth0ViaSocial('facebook')
cy.visit('http://localhost:3000/')
})

it('navigates to the app after navigation and displays the sample project header', () => {
cy.get('h1').should('contain', 'React.js Sample Project')
})
})

Here's a sample of what all 3 should look like in order.

Lastly, we can refactor our login command to take advantage of cy.session() to store our logged in user so we don't have to reauthenticate before every test. This also largely cuts down on the likelihood your account is blocked for frequent authentication attempts. Feel free to DRY this up a bit!

cypress/support/commands.ts
Cypress.Commands.add(
'loginToAuth0ViaSocial',
(SOCIAL_PROVIDER: 'microsoft' | 'google' | 'facebook') => {
const log = Cypress.log({
displayName: 'Social LOGIN',
message: [`🔐 Authenticating | ${SOCIAL_PROVIDER}`],
// @ts-ignore
autoEnd: false,
})
log.snapshot('before')

cy.session(
`social-${SOCIAL_PROVIDER}`,
() => {
switch (SOCIAL_PROVIDER) {
case 'microsoft':
logIntoMicrosoft(
Cypress.env('MICROSOFT_USERNAME'),
Cypress.env('MICROSOFT_PASSWORD'),
Cypress.env('MICROSOFT_NAME')
)
break
case 'google':
logIntoGoogle(
Cypress.env('GOOGLE_USERNAME'),
Cypress.env('GOOGLE_PASSWORD'),
Cypress.env('GOOGLE_NAME')
)
break
case 'facebook':
logIntoFacebook(
Cypress.env('FACEBOOK_USERNAME'),
Cypress.env('FACEBOOK_PASSWORD'),
Cypress.env('FACEBOOK_NAME')
)
break
default:
throw new Error('no social provider configured!')
}
},
{
validate: () => {
cy.visit('http://localhost:3000')
switch (SOCIAL_PROVIDER) {
case 'microsoft':
cy.get('h6.dropdown-header').should(
'contain',
Cypress.env('MICROSOFT_NAME')
)
break
case 'google':
cy.get('h6.dropdown-header').should(
'contain',
Cypress.env('GOOGLE_NAME')
)
break
case 'facebook':
cy.get('h6.dropdown-header').should(
'contain',
Cypress.env('FACEBOOK_NAME')
)
break
default:
throw new Error('no social provider configured!')
}
},
}
)

log.snapshot('after')
log.end()
}
)

With the use of cy.session(), our tests should now run quicker!

We hope this guide was able to get you up and running with cy.origin() and cy.session(). If you ran into any issues while following this guide, or have any feedback, please let us know and submit a Github issue. Happy testing!

See also