A Supabase Edge Function that enables Naver Login with Supabase Custom Provider by proxying Naver's non-standard userinfo API response into standard OIDC format.
Supabase Custom Provider expects a standard OIDC userinfo response:
{ "sub": "abc123", "email": "user@example.com", "email_verified": true, "name": "John" }But Naver's userinfo endpoint (https://openapi.naver.com/v1/nid/me) wraps the response in a non-standard envelope:
{
"resultcode": "00",
"message": "success",
"response": {
"id": "abc123",
"email": "user@example.com",
"name": "홍길동",
"profile_image": "https://..."
}
}This causes Supabase Auth to fail with:
Error getting user email from external provider
Deploy this Edge Function to your Supabase project. It acts as a thin proxy between Supabase Auth and Naver's API — unwrapping the nested response and returning standard OIDC-formatted userinfo.
Client
└→ supabase.auth.signInWithOAuth({ provider: 'custom:naver' })
Supabase Auth
├→ Authorization URL → https://nid.naver.com/oauth2/authorize (direct to Naver)
├→ Token URL → https://nid.naver.com/oauth2/token (direct to Naver)
├→ JWKS URI → https://nid.naver.com/oauth2/jwks (direct to Naver)
└→ Userinfo URL → https://<project>.supabase.co/functions/v1/naver-userinfo (this proxy)
└→ fetches https://openapi.naver.com/v1/nid/me
└→ unwraps { response: { ... } }
└→ returns standard OIDC format
- Go to Naver Developers and create a new application.
- Application name: Your service name
- API selection: Select "네이버 로그인 (Naver Login)"
- Required consent items (critical):
- Go to API 권한관리 (API Permission Management)
- Set 이메일 (Email) to "필수 동의" (Required consent)
- Without this, Naver will not return the user's email and authentication will fail.
- Optionally add 이름 (Name), 프로필 사진 (Profile Image), 별명 (Nickname) as needed.
- Service environment: Add the environments you need:
- PC웹 (PC Web):
- Service URL: Your production domain (e.g.,
https://myapp.com) - Callback URL:
https://<your-project-ref>.supabase.co/auth/v1/callback
- Service URL: Your production domain (e.g.,
- Mobile웹 (Mobile Web) (if applicable):
- Service URL: Same as above
- Callback URL: Same as above
- PC웹 (PC Web):
- Copy your Client ID and Client Secret.
# Clone this repository
git clone https://github.com/<your-org>/supabase-naver-oidc-proxy.git
cd supabase-naver-oidc-proxy
# Login to Supabase CLI (if not already)
supabase login
# Link to your Supabase project
supabase link --project-ref <your-project-ref>
# Deploy the Edge Function
supabase functions deploy naver-userinfo --no-verify-jwtWhy
--no-verify-jwt? This function receives a Naver access token (not a Supabase JWT) in the Authorization header and forwards it to Naver's API. Supabase's built-in JWT verification must be disabled so the Naver token can pass through. Authentication is handled by Naver's own token validation.
After deployment, your function URL will be:
https://<your-project-ref>.supabase.co/functions/v1/naver-userinfo
Go to Supabase Dashboard → Authentication → Sign In / Providers → Custom Providers → Create Custom Auth Provider:
| Field | Value |
|---|---|
| Provider Identifier | naver |
| Display Name | Naver (or 네이버) |
| Configuration Method | Manual configuration |
| Issuer URL | https://nid.naver.com |
| Authorization URL | https://nid.naver.com/oauth2/authorize |
| Token URL | https://nid.naver.com/oauth2/token |
| Userinfo URL | https://<your-project-ref>.supabase.co/functions/v1/naver-userinfo |
| JWKS URI | https://nid.naver.com/oauth2/jwks |
| Client ID | (from Step 1) |
| Client Secret | (from Step 1) |
| Scopes | profile |
| Allow users without email | OFF |
Important configuration notes:
- Manual configuration is required. Auto-discovery mode will use Naver's userinfo endpoint directly, bypassing this proxy, and will fail.
- Scopes must be
profile(notopenid). Usingopenidcauses Supabase to extract user info from the id_token instead of calling the userinfo endpoint, bypassing this proxy entirely.- The Userinfo URL must point to your deployed Edge Function, not to Naver's API directly.
const { error } = await supabase.auth.signInWithOAuth({
// Supabase SDK types don't include custom OIDC providers yet.
// Remove this assertion when @supabase/supabase-js adds custom:* support.
provider: "custom:naver" as "google",
options: {
redirectTo: `${window.location.origin}/auth/callback`,
},
});To allow users who sign in with both Google and Naver (using the same email) to be linked to a single account:
- Go to Supabase Dashboard → Authentication → Sign In / Providers
- Enable "Allow manual linking"
Naver API field (response.) |
OIDC userinfo field | Notes |
|---|---|---|
id |
sub |
Unique user identifier |
email |
email |
Requires "필수 동의" in Naver console |
(always set to true) |
email_verified |
Naver accounts have verified emails |
name |
name |
Real name |
nickname |
nickname |
Display name |
profile_image |
picture |
Avatar URL |
- Check Naver API permissions: Ensure email is set to "필수 동의" (required consent) in your Naver app's API Permission Management.
- Verify Scopes: Must be
profileonly. Do NOT includeopenid— it causes Supabase to skip the userinfo endpoint entirely. - Verify Configuration Method: Must be "Manual configuration", not "Auto-discovery".
- Verify Userinfo URL: Must point to your Edge Function (
https://<project>.supabase.co/functions/v1/naver-userinfo), not Naver's API.
Naver does not support email or other non-standard scopes. Use profile only.
The function was deployed without --no-verify-jwt. Redeploy:
supabase functions deploy naver-userinfo --no-verify-jwtIf you see zero invocations in the Edge Functions dashboard after attempting login, the openid scope is likely included. Supabase extracts user info from the id_token when openid is present and never calls the userinfo endpoint. Remove openid from Scopes.
supabase start
supabase functions serve naver-userinfo --no-verify-jwtTest with curl:
curl http://localhost:54321/functions/v1/naver-userinfo \
-H "Authorization: Bearer <naver-access-token>"When implementing the login button, follow Naver's BI guidelines:
- Background:
#03A94D(Naver green) - Logo and text:
#FFFFFF(white) - Use the N logo icon (do not modify its shape)
- Recommended button text: "네이버로 계속하기" or "Log in with Naver"
MIT