API request for member email

I am making a site where users can log in and access content exclusive to them, and I need access to their email. I have the client running and working, redirecting to my site, etc. All working fine, by following the docs and this helpful post:

All other parameters I am asking for are being returned (full_name, profile pic). Unfortunately the one thing that isn’t being returned is the email. - I believe the error must be when asking for the scopes, since the API does return my email when trying to access from my own account.

This is my code to exchange the login code for a token - I believe the crucial part here being that I am asking for identity[email]:

const getToken = async () => {
	if( clientId && clientSecret && redirectUri ){

		let bodyOptions = {
			code: code,
			grant_type: 'authorization_code',
			client_id: clientId,
			client_secret: clientSecret,
			redirect_uri: redirectUri,
			scopes : 'users pledges-to-me my-campaign identity identity[email]'
		}

		const patreonRequest = await fetch('https://www.patreon.com/api/oauth2/token', {
			method: 'POST',
			body: new URLSearchParams(bodyOptions),
			headers: { 
				'Content-Type': 'application/x-www-form-urlencoded',
			}
		})
		return await patreonRequest.json()
	}
	else {
		throw `Did not have either clientId, clientSecret or redirectUri`
	}
}

And once the user has the token, this is my call to the API to request his information - where I ask for his email under fields[user]:

async function getPatreonData() {
	const patreonRequest = await fetch('https://www.patreon.com/api/oauth2/v2/identity?'+ new URLSearchParams({
	    "fields[user]":"full_name,email,image_url",
	    "include":"memberships",
	    "fields[member]":"currently_entitled_amount_cents,patron_status"
	}),{
		method: 'GET',
		headers: { 
			'Authorization': `Bearer ${token}`
		}
	})
	return await patreonRequest.json()
}

Which is returning all the information requested, except for the email - unless I am accessing from my own account, when it does show up:

{
    "data": {
        "attributes": {
            "full_name": "the users name",
            -- email expected here --
            "image_url": "https:// blabla working fine"
        },
        "id": "1234567890",
        "relationships": {
            "memberships": {
                "data": [
                    {
                        "id": "asdfghjkl-id-okay",
                        "type": "member"
                    }
                ]
            }
        },
        "type": "user"
    },
    "included": [
        {
            "attributes": {
                "currently_entitled_amount_cents": 0,
                "patron_status": null
            },
            "id": "asdfghjkl-id-okay",
            "type": "member"
        }
    ],
    "links": {
        "self": "https:// user link ok"
    }
}

Both functions are running on Lambda, if that makes any difference.
I have tried every combination I can think of, asking for minimal scopes, asking for everything, space-separated, comma-separated… I’m pretty sure the bug has to be in the scopes, but can’t figure it out for the life of me.

edit: Is this maybe related to a user’s email being validated? Or made public in the user’s settings page?

If anyone can throw me any help, it would be enormously appreciated.
Cheers,

Solved it for myself!
Leaving it up in case it helps anyone in the future, but essentially:

  • Read the documentation :man_facepalming:
  • The scopes go in the login button, not at the code exchange
  • It’s “scope” not “scopes”… :man_facepalming::man_facepalming:
  • Programmer tunnel vision is a thing.
1 Like