Search code examples
reactjsexpressoauth-2.0corsgoogle-oauth

Access to fetch at https://accounts.google.com/o/oauth2/v2/auth has been blocked by CORS


I'm sending fetch from React to Express to authenticate with Google but I've been getting access blocked by CORS error. I'm redirecting the POST request from React to the Google URL for authentication. I tried using cors in the express app but I'm still getting the same error. For fetching

const handleClick = (e) => {
    fetch('http://localhost:8000/api/mail/login', {
        method: 'POST'
    })
    .then(res => res.text())
}

Using cors in express app.js

app.use(cors())

Trying to redirect to google auth

const oauth2Client = new google.auth.OAuth2(
    process.env.CLIENT_ID,
    process.env.CLIENT_SECRET,
    process.env.REDIRECT_URI
)

const url = oauth2Client.generateAuthUrl({
    access_type: 'offline',
    scope: process.env.SCOPE
})

const gmail = google.gmail({
    version: 'v1',
    auth: oauth2Client
})

router.post('/login', (req, res, next) => {
    res.redirect(url)
})

The error: Access to fetch at 'https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&scope=https%3A%2F%2Fmail.google.com%2F&response_type=code&client_id=727520060136-ngpfd4ll798v42gfclh7cms9ndqstt32.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A8000' (redirected from 'http://localhost:8000/api/mail/login') from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.


Solution

  • The authentication flow must happen in a visible browsing context, not with a fetch request. In other words: You must navigate the current tab to (or open a new tab at) http://localhost:8000/api/mail/login, the tab will then be redirected to https://accounts.google.com/o/oauth2/v2/auth?... and this page becomes visible. Now the user must interact with that page to choose/confirm their Google account, after which they will be redirected to a page on your server with an authorization code in the URL (for example, http://localhost:8000/callback?code=...) and your server must exchange the authorization code for an access token with a server-to-server call.

    When made like this, none of the requests made is cross-origin, so no CORS will be involved at all.

    Instead of the handleClick function, you need a login form like

    <form action="http://localhost:8000/api/mail/login" method="post">
      <input type="submit" value="Press to log in"/>
    </form>