Development··3 min read

The Nightmares I Encountered Implementing OAuth

I didn't expect social login to be this complicated. A war story from implementing OAuth with Kakao, Google, and Apple.

Social login -- should take a day, right?

That's what I thought. I estimated 2 days for implementing three social logins: Kakao, Google, and Apple. It ended up taking 8 days. 4x over budget.

The OAuth 2.0 spec itself is simple. Get an Authorization Code, exchange it for an Access Token, fetch user info. Done. But each platform implements it slightly differently, and that's where things get messy.

Kakao was the smoothest

The Kakao developer docs are in Korean, so they were easy to read. Setting up the Redirect URI, exchanging tokens via REST API, fetching user info -- about 4 hours total.

But there was one catch. Email consent is optional, so if the user declines, you don't get their email. Our system was email-based, which meant sign-up was impossible without one. I had to build an extra flow to manually collect the email from users who didn't consent.

(If I'd known this upfront, the design would've been different from the start.)

Google's token management is annoying

Google's implementation was straightforward, but the Refresh Token policy was strict. You only get a Refresh Token on the first authentication. After that, nothing. You need access_type=offline with prompt=consent to get a Refresh Token every time, but then the user sees the consent screen on every login.

Not knowing this, I didn't save the Refresh Token. When existing users' tokens expired after 1 hour, they all got logged out. 72 users simultaneously sent "I got logged out" support tickets.

Apple is a whole different dimension

Apple was the real nightmare. First, you need an Apple Developer Program membership ($99), then create a Service ID, verify your domain, get a Private Key, and manually build a JWT.

During token exchange, the client_secret isn't a plain string -- it's a JWT. This JWT needs to be signed with the ES256 algorithm, and I'd never written ES256 signing code in Node.js before. I read the jsonwebtoken library docs 3 times.

And Apple only gives you user info (name, email) once. On the first authentication. Miss it and you're done. While testing, I missed it and had to revoke the Apple ID app connection and start over from scratch. Just figuring out how to revoke the connection took 20 minutes.

The account merging problem

What happens when a user signs up with Kakao and then logs in with Google? If the email is the same, should they be treated as the same account? Or separate accounts?

Not defining this policy before starting implementation was a mistake. We later switched to suggesting account linking when emails match, but by then 23 duplicate accounts had already been created. Merged them manually.

What I learned

Before implementing OAuth, you absolutely must decide: fallback plan when email is unavailable, account merging policy, Refresh Token management strategy, and platform-specific quirks. Sort this out before writing a single line of code.

If I had to do this again, I'd honestly just use a library like NextAuth (now Auth.js). Building it myself taught me a lot, but I could've spent that time building other features.

Related Posts