Authenticating with the API

You're building a genetic app. How do you get a user's data? With OAuth 2.0,

  1. Ask the user's permission for their data. If they accept, you get an authorization code.
  2. Exchange the code for an authorization token.
  3. Using the token, call our API endpoints for data.

1. Ask the user's permission, get an authorization code.

In your app, send the user to with these parameters:

redirect_uri The redirect uri from your dashboard, e.g.
response_type code
client_id The client id from your dashboard.
scope A space-delimited list of scopes you're asking the user to allow you to access. See scopes for a list of them.
state An optional value of your choosing, to maintain state between the request and the callback.
code_challenge code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier))), where code_verifier is a random url-safe string of between 43-128 characters, to specify a Proof Key for Code Exchange (PKCE). This is required if your client is a mobile app that needs to use a mobile scheme in its redirect_uri.
select_profile=True Optional. 23andMe user accounts may have multiple associated profiles. If you'd like your app to deal with only a single profile's resources, set this parameter to true, and the grant screen will require the user to select a single profile for which to authorize your app. Otherwise, your token will be scoped for all profiles for the user's account.

We recommend you use a branded button so users recognize the login, but you may also use a GET link, or even a form that POSTs to /authorize/ (helpful for scopes with thousands of rsids that won't fit in a URL string).

<a href=" rs123">Connect with 23andMe</a>

When the user clicks the button, they sign in with 23andMe and see a screen asking them to give you access to their data. If they accept, their browser will redirect to your redirect_uri with parameter code=zzz. That's your authorization code, and it only lasts for 10 minutes.

2. Exchange the auth code for a token.

Send a POST /token/ request with these parameters (client_id and client_secret are on your dashboard):

    curl \
        -d client_id=xxx \
        -d client_secret=yyy \
        -d grant_type=authorization_code \
        -d code=zzz \
        -d "redirect_uri=https://localhost:5000/receive_code/" \
        -d "scope=basic%20rs3094315" \
        -d "code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk" # if using PKCE

If successful, you'll get a 200 JSON response like this:

     "expires_in": 86400,
     "scope":"rs3094315 basic"}

Otherwise, you'll get a non-200 error response. Here's a full list of errors.

    {"error_description":"No such code: 1928789",

3. Call the API endpoints.

Now that you've got a token, call the endpoints you want data from. See the API reference for endpoints and explanations.

Refresh tokens

Access tokens expire after 1 day. If you need to access a user's data past that, you can request another token using the last refresh_token that you were issued. Using the refresh token means you don't have to send the user through the "Accept" screen all over again. Requesting a new token set will invalidate your old refresh_token. Be sure to specify the full scope when requesting a new access token.

    curl \
         -d client_id=xxx \
         -d client_secret=yyy \
         -d grant_type=refresh_token \
         -d refresh_token=33c53cd7bb \
         -d "redirect_uri=https://localhost:5000/receive_code/" \
         -d "scope=basic%20rs3094315"

You will get the same JSON responses as when you got the original token.


With OAuth 2.0, you include a space-delimited list of scopes in your requests to access certain user data. The user must consent to each scope. For example, if you wanted profile markers rs123 and rs456, your scope would be basic names email rs123 rs456; you would need basic, names and email to get the user's profile and associated id, and rs123 and rs456 to get those profile markers for the profile.

The privacy of our users and the protection of their data are among 23andMe's highest priorities. With that in mind, be sure to request only the scopes that your app needs. For example, if you know which SNPs you'll be using, please request the scopes for only those SNPs and not the entire genome.

If you are using the deprecated API endpoints, check here for a list of supported scopes.

scope what it grants access to, and what the user sees when you ask for it
basic Read your profile's service type (ancestry or health and ancestry) and whether or not your profile has been genotyped
names Read the full name on your account and profile
email Read your account's email address
profile:image Read your profile's picture
report:all Read all of your profile's reports
report:genetic_weight Read your profile's Genetic Weight report
report:wellness.alcohol_flush_reaction Read your profile's Alcohol Flush Reaction report
report:wellness.caffeine_consumption Read your profile's Caffeine Consumption report
report:wellness.deep_sleep Read your profile's Deep Sleep report
report:wellness.lactose Read your profile's Lactose Intolerance report
report:wellness.muscle_composition Read your profile's Muscle Composition report
report:wellness.saturated_fat_and_weight Read your profile's Saturated Fat and Weight report
report:wellness.sleep_movement Read your profile's Sleep Movement report
rsXX or iXX The genotype at rsXX or iXX for all profiles in the account. You can string these together to get access to multiple genes. This list of SNPs (44MB) shows which SNPs our customers are genotyped for; all of these SNPs are valid scopes.
accession:<accession_id> Read your profile's genotype across accession accession_id, unless you have not opted to know it
genomes Read your profile's entire genome, including all SNP locations except those the profile has not opted into. You should only grant access to services you trust.
phenotypes:read:all Read all of your profile's phenotypes. You should only grant access to services you trust.