Backend Developer · Focus area 3: Security and sign-in

BE5: Sign-in with OAuth 2 and OpenID Connect

Goal: understand and use the standard sign-in protocols: tell sign-in from permission, follow the authorization code flow with PKCE, know what ID tokens and access tokens are for, check access tokens properly in an API, and handle refresh, sign-out and machine-to-machine access.

You'll need: Module 44 (authentication) and Module 74 (authentication and authorisation), BE1, and the TiffinBox kit with the practice sign-in server running (npm run sim).

Where this is used: "Sign in with Google", a bank app's login, a company's single sign-on to dozens of internal tools, and one service calling another. Nearly every modern app hands sign-in to an identity provider through OAuth 2 and OpenID Connect.

How it differs: a cybersecurity specialist tests and attacks sign-in systems. A backend developer builds the API side: accepting only valid tokens, for the right API, with the right permissions, and doing it with well-tested libraries instead of home-made code.

Time: reading about 2 hours · practice (the Try it tasks) about 3 hours · assignment about 3 to 4 hours.

Lessons

  1. 1Who you are, and what you may doReading 15–25 minutes, plus practice✓
  2. 2The authorization code flow with PKCEReading 15–25 minutes, plus practice✓
  3. 3ID tokens, access tokens and scopesReading 15–25 minutes, plus practice✓
  4. 4Checking access tokens in an APIReading 15–25 minutes, plus practice✓
  5. 5Refresh, sign-out and machine accessReading 15–25 minutes, plus practice✓

🛠️Assignment: Sign-in for TiffinBox

This completes the sign-in part of Project 1.

  1. Draw the authorization code flow with PKCE for tiffin-web, labelling each request, parameter and token.
  2. Decode an access token and an ID token from the kit and explain every claim.
  3. Rebuild api/auth.js to verify tokens with the JWKS (signature, algorithm, issuer, audience, expiry) and check scopes.
  4. Show refresh token rotation and a client credentials token in action.
  5. Write the token lifetimes and revocation plan you'd recommend for TiffinBox's app, tablets and services.

Self-check before you finish:

✅Module check

Explain in a few sentences, in your own words:

How does an API know a request comes from a signed-in user with permission, using OAuth 2 and OpenID Connect?

Show a good answer

A good answer mentions: authentication versus authorisation, and an identity provider instead of home-made passwords; the authorization code flow with PKCE, exact redirect URIs and state; ID tokens for the client (aud = client ID) versus access tokens for the API (aud = API), scopes as permissions, and JWT payloads being readable by anyone; verifying every token with a library against the IdP's JWKS, with fixed algorithms and checks of issuer, audience and expiry, then scopes, returning 401 or 403; and short-lived access tokens, rotating refresh tokens, revocation, and client credentials for machines.

📚Official references

Official documentation and guidance for this module's topics, chosen on 2 November 2026. Tools, laws and standards change, so check the current version before you rely on a detail. If a link has moved, search the same site.

📝Module quiz

10 questions · 10 marks each · 100 marks in all · pass mark 70% · retry as often as you like ·

1. A hospital app's API returns 401 both when there's no token and when a nurse's valid token lacks permission to view billing. What should change?

Why each option is right or wrong

  • “Return 404 for both, so attackers learn nothing” (Incorrect): Hiding everything behind 404 confuses legitimate apps about what to fix.
  • “Return 500 when permission is missing, since the server refused” (Incorrect): Refusing a request isn't a server error.
  • “Return 200 with an empty list when permission is missing” (Incorrect): Pretending there's no data hides a permission problem and confuses users.
  • “401 for a missing or bad token; 403 for no permission” is correct.

    401 asks the client to authenticate; 403 says "you're signed in, but not allowed". Apps react differently: sign in again versus show "no access".

    • Add: WWW-Authenticate with insufficient_scope on 403.
    • Covered in detail: in BE6.

📖 Revise: Lesson 1: Who you are, and what you may do

Question ID sp-backend-05-q1 · Report a mistake in this question
2. A team wants its mobile app to collect the user's identity-provider password in its own login screen and send it to the IdP for a token. What's the recommended approach instead?

Why each option is right or wrong

  • “Encrypt the password in the app before sending it” (Incorrect): The app still handles the IdP password, which is what the standard avoids.
  • “Store the password on the phone so users sign in only once” (Incorrect): Storing passwords on the device adds risk and still uses the discouraged flow.
  • “Use the implicit flow, which returns the token straight away” (Incorrect): The implicit flow puts tokens in URLs and is not recommended.
  • “The code flow with PKCE, signing in at the IdP” is correct.

    The user signs in on the IdP's page; the app gets a one-time code and exchanges it with its PKCE verifier. The app doesn't see the password.

    • OAuth 2.1 guidance: the password grant and implicit flow are not recommended.
    • Bonus: the IdP can add one-time codes or passkeys without app changes.

📖 Revise: Lesson 2: The authorization code flow with PKCE

Question ID sp-backend-05-q2 · Report a mistake in this question
3. An attacker intercepts the authorization code on its way back to a mobile app. The app uses PKCE. What happens when the attacker tries to exchange the code?

Why each option is right or wrong

  • “The exchange works, because codes are valid for anyone who holds them” (Incorrect): That's the risk PKCE removes.
  • “The IdP asks the user to confirm on their phone first” (Incorrect): Some IdPs add prompts, but that isn't how PKCE protects the code.
  • “The attacker gets a token with fewer scopes” (Incorrect): They get no token at all.
  • “It fails: the attacker lacks the code verifier” is correct.

    The token endpoint checks the verifier against the challenge sent at the start. Without the verifier, the code is useless.

    • Plus: codes are one-time and short-lived.
    • The app also checks: state, so forged callbacks are refused.

📖 Revise: Lesson 2: The authorization code flow with PKCE

Question ID sp-backend-05-q3 · Report a mistake in this question
4. A developer sends the ID token from sign-in to the orders API as the bearer token. The API reads name from it and shows orders. What's wrong?

Why each option is right or wrong

  • “Nothing; both tokens are signed by the same IdP” (Incorrect): Same signer, different purpose and audience.
  • “ID tokens are too large to send in a header” (Incorrect): Size isn't the issue.
  • “The API should decrypt the ID token before reading it” (Incorrect): ID tokens are signed, not encrypted; the problem is using the wrong token.
  • “APIs need access tokens with the API as audience” is correct.

    An ID token's aud is the client app; it tells the app who signed in. An access token's aud is the API and carries scopes.

    • Check: aud on every request, which rejects ID tokens automatically.
    • Use scopes: to decide what the caller may do.

📖 Revise: Lesson 3: ID tokens, access tokens and scopes

Question ID sp-backend-05-q4 · Report a mistake in this question
5. A company's payments API accepts any token signed by the company's identity provider. A token issued for the HR tool works on the payments API. Which check is missing?

Why each option is right or wrong

  • “The expiry check on the token's exp claim” (Incorrect): The HR token may be fresh; expiry doesn't stop it.
  • “The signature check against the IdP's keys” (Incorrect): The signature is genuine; the token simply wasn't meant for this API.
  • “The token's length, which differs between apps” (Incorrect): Length says nothing about who the token is for.
  • “The audience (aud) check” is correct.

    Tokens are issued for a specific audience. Without checking aud, any valid token from the same IdP is accepted.

    • Also check: iss, signature and allowed algorithms.
    • Then: scopes for the route.

📖 Revise: Lesson 3: ID tokens, access tokens and scopes

Question ID sp-backend-05-q5 · Report a mistake in this question
6. A starter API decodes the JWT payload with JSON.parse(Buffer.from(part, 'base64url')) and uses sub. What can an attacker do?

Why each option is right or wrong

  • “Nothing, because JWTs are encrypted” (Incorrect): Standard JWTs are only encoded; anyone can read and write the payload.
  • “Read other users' passwords from the token” (Incorrect): Tokens don't contain passwords; the danger is forged identities.
  • “Only slow down the API with long tokens” (Incorrect): The bigger problem is impersonation.
  • “Forge a token with any user and scopes” is correct.

    Without verifying the signature against the IdP's keys, the API trusts any payload. Forged tokens work.

    • Fix: verify with a library and the JWKS, checking issuer, audience, expiry and algorithm.
    • Test: a token signed with a different key must get 401.

📖 Revise: Lesson 4: Checking access tokens in an API

Question ID sp-backend-05-q6 · Report a mistake in this question
7. An identity provider rotates its signing keys. Afterwards, an API rejects every new token until someone restarts it. What's the likely cause?

Why each option is right or wrong

  • “The API checks the exp claim too strictly after rotation” (Incorrect): Expiry doesn't change with key rotation.
  • “Key rotation breaks every API for a day” (Incorrect): Well-built APIs handle rotation without downtime.
  • “The new keys use a different alphabet” (Incorrect): Keys are standard JWK format; the format didn't change.
  • “Its cached keys lack the new kid; it should refetch” is correct.

    New tokens name a new key ID. The API should cache keys but fetch the JWKS again when a token's kid isn't in its cache.

    • Libraries: such as jose's remote JWKS, do this for you.
    • Avoid: fetching on every request, which is slow.

📖 Revise: Lesson 4: Checking access tokens in an API

Question ID sp-backend-05-q7 · Report a mistake in this question
8. An API lets the token header decide the algorithm. An attacker sends "alg": "HS256" signed with the IdP's public key used as a secret. Why can this work, and what's the fix?

Why each option is right or wrong

  • “HS256 is a weaker hash, so the attacker can guess the signature quickly” (Incorrect): It isn't about guessing; the attacker knows the key being used.
  • “The token is too short for RS256” (Incorrect): Length is irrelevant here.
  • “Public keys must be kept secret to prevent this” (Incorrect): Public keys are meant to be public; the fix is on the verifying side.
  • “The verifier lets the token choose HMAC; fix the algorithm list” is correct.

    The public key is public, so anyone can make an HMAC with it. If the API lets the token pick HS256, it accepts the forgery.

    • Fix: pass algorithms: ['RS256'] (or your IdP's algorithm) to the verifier.
    • Also reject: alg: none.

📖 Revise: Lesson 4: Checking access tokens in an API

Question ID sp-backend-05-q8 · Report a mistake in this question
9. A laptop with a saved 30-day access token is stolen. The company can't stop the token working. What design would have limited the damage?

Why each option is right or wrong

  • “Longer passwords for all staff” (Incorrect): Passwords don't help once a token has been issued and stolen.
  • “Encrypting the saved token inside the laptop's browser storage” (Incorrect): The thief has the laptop; the browser decrypts it for them.
  • “Switching to ID tokens instead of access tokens” (Incorrect): ID tokens aren't for APIs and wouldn't help.
  • “Short access tokens, rotating refresh tokens, revocation” is correct.

    A short access token stops working within minutes; revoking the refresh token at the IdP prevents new ones.

    • For high-risk actions: check revocation or introspect the token.
    • Rotation: reveals a stolen refresh token when both copies are used.

📖 Revise: Lesson 5: Refresh, sign-out and machine access

Question ID sp-backend-05-q9 · Report a mistake in this question
10. A nightly job sends payment reminders by calling the API with a manager's saved login token. What's the better design?

Why each option is right or wrong

  • “Give the job the manager's password so it can sign in fresh each night” (Incorrect): That spreads a person's password into a machine and breaks when they change it.
  • “Make the manager's token last for years” (Incorrect): Long-lived tokens are the risk this module warns about.
  • “Turn off authentication for the reminders route at night” (Incorrect): An unprotected route is open to everyone, not just the job.
  • “Client credentials with the job's own ID, secret and narrow scopes” is correct.

    Machines get their own identity. Its token carries only the scopes the job needs, and it doesn't depend on any person's account.

    • Store: the client secret in a secret manager.
    • Audit: logs show client:reminder-job, not the manager.

📖 Revise: Lesson 5: Refresh, sign-out and machine access

Question ID sp-backend-05-q10 · Report a mistake in this question

ProLearners Assist