Auth & Security63 min total · 19 parts
OAuth 2.0 and JWT Explained: What Really Happens When You Click "Sign In"
Part 8 of 19 · ~2 min
Scopes and Consent
A scope is one specific, named permission a client is requesting — profile, calendar.readonly, tasks:write. Without scopes, Priya would have exactly one choice on that consent screen: give Tasklight everything Kestrel could possibly hand over, or give it nothing. Scopes are what turn that into a list she can actually read and judge item by item — this app wants your name and email, this app also wants to peek at your calendar's free/busy times — rather than one blanket yes-or-no gate.
GET https://id.kestrel.example/oauth/authorize
?client_id=tasklight-web
&redirect_uri=https://app.tasklight.dev/auth/callback
&response_type=code
&scope=openid%20profile%20email%20calendar.readonly
&state=8f2a1c9d4b
&code_challenge=XQ0tcQDLtZmE5Z-zbXwzpYhOn0dnU4ZCmBdtuF8kXQQ
&code_challenge_method=S256
That calendar.readonly is there for one reason: Tasklight can optionally set a reminder the day before a task's due date, by reading the free/busy slots on Priya's calendar. Notice which scope it did not ask for — plain calendar, which would have also handed over read-write access to the actual contents of her events, titles, attendees, and all. Nothing about a due-date reminder needs any of that; knowing a slot is busy is the entire feature. Asking for exactly the permission a feature uses, and nothing wider, is called the principle of least privilege, and the payoff shows up twice — once on the consent screen Priya actually reads, and again, much later, if that particular token ever leaks and an attacker discovers there was nothing more valuable behind it than free/busy times. None of that checking stops once Priya clicks approve, either: tasks-service and billing-service both look at the scope a token actually carries on every request they get, separately from checking whether the token is valid at all — a correctly signed, unexpired token can still be turned away for asking to do something it was never granted.
Tasklight didn't always ask for calendar.readonly only when it was needed. The first version requested it for every single user at signup, whether or not they ever turned on due-date reminders, on the reasoning that asking once up front was simpler than asking twice. It technically was simpler — for Tasklight. For Priya, it meant a scarier consent screen on day one, for a feature she might never touch, before she'd seen enough of the product to trust it with her calendar. The fix was incremental authorization: request openid profile email at signup, and only send Priya back through a second, narrower consent screen — asking for calendar.readonly specifically — the moment she actually flips on due-date reminders. Same eventual permissions, a consent screen that matches what she's actually agreeing to at the moment she's agreeing to it, and no calendar access sitting on a token for users who never use the feature it's for.