Skip to content

Conversation

@johndpope
Copy link

@johndpope johndpope commented Dec 23, 2024

What kind of change does this PR introduce?

This implementation allows linking identities using ID tokens. Here's what it provides:

A new endpoint for linking identities using ID tokens
Support for various OIDC providers (Google, Apple, etc.)
Proper validation of ID tokens including audience and nonce checks
Transaction handling for safe database updates
Audit logging of identity linking
Error handling consistent with the existing codebase

UPDATE

tests - for apple (TODO - extend to a few more google / facebook - help wanted)

User creation with email identity
Session and access token generation
Mocking of Apple ID tokens
Identity linking verification
Error case handling
Metadata verification

What is the current behavior?

#313

What is the new behavior?

TESTING NOTES

dockercompose.yml

  auth:
    container_name: supabase-auth
#    image: supabase/gotrue:v2.164.0
    image: auth:local  
git clone https://www.github.com/johndpope/auth 
cd auth
docker build -t auth:local -f Dockerfile

back in supabase

docker compose up auth --remove-orphans

Apple OAuth config

GOTRUE_EXTERNAL_APPLE_ENABLED="true"
GOTRUE_EXTERNAL_APPLE_CLIENT_ID="com.supabase.auth"
GOTRUE_EXTERNAL_APPLE_SECRET="any_test_secret"
GOTRUE_EXTERNAL_APPLE_REDIRECT_URI="http://localhost:9999/callback"

manualy add user in dashboard

curl -X POST 'http://localhost:8000/auth/v1/token?grant_type=password' \
-H "apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE" \
-H "Content-Type: application/json" \
-d '{
  "email": "[email protected]",
  "password": "test1234!"
}'


eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJlMTBkY2E1My01ODA3LTQzODktYjU1Yy02OWJiOTkwYjRhODIiLCJhdWQiOiJhdXRoZW50aWNhdGVkIiwiZXhwIjoxNzM1Mjc2ODQwLCJpYXQiOjE3MzUyNzMyNDAsImVtYWlsIjoianBAYmVsbGdlb3JnZS5jb20iLCJwaG9uZSI6IiIsImFwcF9tZXRhZGF0YSI6eyJwcm92aWRlciI6ImVtYWlsIiwicHJvdmlkZXJzIjpbImVtYWlsIl19LCJ1c2VyX21ldGFkYXRhIjp7ImVtYWlsX3ZlcmlmaWVkIjp0cnVlfSwicm9sZSI6ImF1dGhlbnRpY2F0ZWQiLCJhYWwiOiJhYWwxIiwiYW1yIjpbeyJtZXRob2QiOiJwYXNzd29yZCIsInRpbWVzdGFtcCI6MTczNTI3MzI0MH1dLCJzZXNzaW9uX2lkIjoiZTExNmRjNWMtMDhkYi00ZTBkLThlNmQtZWY3MTIwMmEzZWVmIiwiaXNfYW5vbnltb3VzIjpmYWxzZX0.uEXnuIbWq4XNEBw5dtQfCCpzBJ6MZLQcuaQkOddGZpI



curl -X POST 'http://localhost:8000/auth/v1/user/identities/link_token' \
-H "apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJlMTBkY2E1My01ODA3LTQzODktYjU1Yy02OWJiOTkwYjRhODIiLCJhdWQiOiJhdXRoZW50aWNhdGVkIiwiZXhwIjoxNzM1Mjc2ODQwLCJpYXQiOjE3MzUyNzMyNDAsImVtYWlsIjoianBAYmVsbGdlb3JnZS5jb20iLCJwaG9uZSI6IiIsImFwcF9tZXRhZGF0YSI6eyJwcm92aWRlciI6ImVtYWlsIiwicHJvdmlkZXJzIjpbImVtYWlsIl19LCJ1c2VyX21ldGFkYXRhIjp7ImVtYWlsX3ZlcmlmaWVkIjp0cnVlfSwicm9sZSI6ImF1dGhlbnRpY2F0ZWQiLCJhYWwiOiJhYWwxIiwiYW1yIjpbeyJtZXRob2QiOiJwYXNzd29yZCIsInRpbWVzdGFtcCI6MTczNTI3MzI0MH1dLCJzZXNzaW9uX2lkIjoiZTExNmRjNWMtMDhkYi00ZTBkLThlNmQtZWY3MTIwMmEzZWVmIiwiaXNfYW5vbnltb3VzIjpmYWxzZX0.uEXnuIbWq4XNEBw5dtQfCCpzBJ6MZLQcuaQkOddGZpI" \
-H "Content-Type: application/json" \
-d '{
  "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY29tLnN1cGFiYXNlLmF1dGgiLCJleHAiOjE3MDM2NjE5NDQsImlhdCI6MTcwMzY2MTY0NCwic3ViIjoiMDAwNzI3LmRjYjYzZDc4ZGZlNTQyYzU4YjRiYWM5ZjY4M2FhMzI3LjA3MTciLCJhdF9oYXNoIjoiZ0J4THUyX3c1VHFfcWY2UFVGSHpBUSIsImVtYWlsIjoianBAYmVsbGdlb3JnZS5jb20iLCJlbWFpbF92ZXJpZmllZCI6InRydWUiLCJpc19wcml2YXRlX2VtYWlsIjoidHJ1ZSIsImF1dGhfdGltZSI6MTcwMzY2MTY0NH0.SIGNATURE",
  "provider": "apple"
}'

client implementation

const linkIdentityWithIdToken = async (idToken: string, provider: string) => {
  const response = await fetch('/user/identities/link_token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${accessToken}`
    },
    body: JSON.stringify({
      id_token: idToken,
      provider: provider
    })
  })
  return response.json()
}

example

import * as AppleAuthentication from 'expo-apple-authentication'

// Link Apple identity to existing user
const linkAppleIdentity = async () => {
  try {
    const credential = await AppleAuthentication.signInAsync({
      requestedScopes: [
        AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
        AppleAuthentication.AppleAuthenticationScope.EMAIL,
      ],
    })
    
    const { user, error } = await linkIdentityWithIdToken(
      credential.identityToken,
      'apple'
    )
    
    if (error) throw error
    return user
  } catch (error) {
    console.error('Error linking Apple identity:', error)
    throw error
  }
}

@johndpope johndpope requested a review from a team as a code owner December 23, 2024 23:32
@johndpope johndpope changed the title link identities by token feat: link identities by token Dec 24, 2024
@cstockton cstockton added enhancement New feature or request For discussion To discuss during next Auth catchup labels Jan 23, 2025
@johndpope johndpope closed this Mar 11, 2025
@mly-johndpope
Copy link

mly-johndpope commented Mar 12, 2025

so github has introduced a function to reset code with a discard commits to force a sync - so i pressed not realizing this other work - so code's gone - ooops

will see if i have a backup somewhere

@kirin0926
Copy link

real need linkIdentityWithIdToken!!!!!!!!!!!!
plz updata

@XanderZhu
Copy link

Any update on this issue?
I really need linkIdentityWithIdToken. Usual linkIdentity allows to login only via browser. For mobile application this way is not preferred.
I would like to request google id token via it's native UI, and then pass it to supabase linkIdentity, like with signInWith.

@johndpope johndpope reopened this Apr 25, 2025
@johndpope
Copy link
Author

sorry this code / pr is here - ideally Supabase officially implements this
#2002

maybe able to self host the backend on an ec2 box
i burn a lot of time attempting to get supabase to work with rds - but only partial success (not working with realtime)
https://github.com/johndpope/rds-supabase

@johndpope johndpope closed this Apr 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request For discussion To discuss during next Auth catchup

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants