Skip to content

Intermediate · Authentication and authorization · topic 34 of 54 · 30 min

Login with Google, OTP and passkeys

Explanation

"Login with Google" uses OAuth 2.0 and OpenID Connect: Google checks the user and sends your backend a signed proof of who they are. OTP login sends a short one-time code by SMS or email, which is very common in India. Passkeys are the modern passwordless option, using a key stored safely on the user's phone.

Login with Google: the idea

OAuth 2.0 is a standard that lets a user give an app limited access to their account on another service, without giving away their password. OpenID Connect (OIDC) is a layer on top that also tells the app who the user is, through an ID token (a signed JWT).

Think of it like this: OAuth is like a valet key for a car. You give the parking attendant a key that only starts the car and opens the door, not the boot or the glove box. Your app gets a "valet key" from Google that only lets it see the user's name and email, never their Gmail password.

The authorization code flow with PKCE

  1. The user taps "Continue with Google".
  2. Your backend makes a random state value and a random code_verifier, plus code_challenge = SHA-256 of the verifier. It saves them in the session.
  3. The browser is sent to Google with client_id, redirect_uri, scope=openid email profile, state and code_challenge.
  4. The user logs in at Google (not on your site) and agrees to share their email and profile.
  5. Google redirects back to your redirect_uri with ?code=...&state=....
  6. Your backend checks state, then sends the code, the code_verifier and its client secret to Google's token endpoint, server to server.
  7. Google returns an ID token. Your backend verifies it (signature, iss, aud, exp), finds or creates the user by the sub claim, and starts its own session.
output
https://accounts.google.com/o/oauth2/v2/auth
  ?response_type=code
  &client_id=1234.apps.googleusercontent.com
  &redirect_uri=https://myshop.in/auth/google/callback
  &scope=openid%20email%20profile
  &state=Zx81kq...
  &code_challenge=E9Melhoa2Owv...
  &code_challenge_method=S256
Step 3: the link the browser opens. PKCE makes a stolen code useless without the verifier.
Careful: Always check that state matches and verify the ID token before trusting it. Use a well-known library (openid-client, Auth.js, Passport or your framework's auth module) instead of writing the flow by hand.

OTP login

An OTP (one-time password) is a short code, usually 6 digits, sent by SMS, WhatsApp or email. Many Indian apps let you log in with just a mobile number and an OTP. In India, business SMS must go through a DLT-registered sender and template (a TRAI rule), so teams usually use a provider such as MSG91, Twilio or Firebase Authentication.

  • Random: made with a secure random generator (crypto.getRandomValues or crypto.randomInt), never Math.random.
  • Short life: expires in about 5 minutes.
  • Limited attempts: after 3 to 5 wrong tries, the code is dead and a new one is needed.
  • Stored hashed: keep only a hash of the OTP, like a password, and delete it after use.
  • Rate limited: for example one SMS per 30 seconds and a few per hour per number, to stop abuse and SMS bills.
javascript
// Example only: runs on a server with Node.js
import { randomInt, createHmac } from 'node:crypto';

const otp = String(randomInt(0, 1000000)).padStart(6, '0'); // '000000' to '999999'
const otpHash = createHmac('sha256', process.env.OTP_SECRET).update(phone + ':' + otp).digest('hex');

await db.otps.insert({ phone, otpHash, expiresAt: Date.now() + 5 * 60 * 1000, attempts: 0 });
await sms.send(phone, 'Your login code is ' + otp + '. It expires in 5 minutes.');
Make the OTP with a secure random number, store only its hash with an expiry and attempt count.
Careful: Never return the OTP in the API response or write it to logs. And give the same reply whether or not the phone number has an account, so attackers cannot discover who is registered.

Passkeys: no password at all

A passkey uses WebAuthn, a web standard. The phone or laptop makes a key pair for your site: the private key stays on the device, unlocked by fingerprint, face or screen lock, and the server stores only the public key. At login the device signs a challenge from the server. Passkeys cannot be phished, because the browser only uses them on the real domain.

MethodStrengthWeak point
Password + hashFamiliar to everyoneReused and phished passwords
SMS OTPEasy, no password to rememberSIM swap, SMS cost, delays
Login with GoogleNo password stored by youDepends on another company
PasskeyPhishing-proof, fastUsers still learning it; needs a fallback
Tip: A good 2026 setup: passkeys first, "Continue with Google" or OTP as fallback, and a password option for those who want it.

Watch the lesson

Login with Google, OTP and passkeys · 1/6

Google login | OTP | Passkeys

Not every login needs a password. Today: Login with Google, OTP and passkeys.

Prefer a video by a teacher? Find free videos on “oauth 2.0 and openid connect explained simply” on YouTube ↗

In real life: Logging in to a grocery app with your mobile number

A quick-commerce grocery app asks only for your mobile number. The backend checks the rate limit, makes a 6-digit code with a secure random generator, saves its hash with a 5-minute expiry, and sends it through a DLT-registered SMS template. You type the code; the backend compares hashes, counts the attempt, deletes the OTP after success and starts a session. Typing a wrong code five times blocks that code, so nobody can guess all million combinations.

Practice (0/2 done)

Task 1 · Code · Javascript

Write generateOtp() that returns a random 6-digit string such as "042917" (leading zeros kept). Use crypto.getRandomValues, not Math.random. Tip: take a random 32-bit number and use % 1000000, then padStart(6, "0").

Task 2 · Code · Javascript

Write verifyOtp(record, code, now). record is { code, expiresAt, attempts }. Check in this order: if record.attempts >= 5 return "locked"; if now > record.expiresAt return "expired"; if code is wrong, add 1 to record.attempts and return "wrong"; otherwise return "ok". (Real apps store a hash of the OTP; here it is plain to keep the task small.)

Quick quiz

Question 1

1.What does OpenID Connect add on top of OAuth 2.0?

Question 2

2.In the authorization code flow, where does the user type their Google password?

Question 3

3.Which is the right way to make an OTP?

Question 4

4.Why limit OTP attempts to about 5?

Question 5

5.Why are passkeys hard to phish?

Read more (free)

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

← Previous: JSON Web Tokens (JWT)