Authentication vs Authorization
People use these two words interchangeably and it causes confusion in every team that builds software. They are different, and the difference matters.
In one line each
- Authentication — who are you?
- Authorisation — what are you allowed to do?
That is it. The rest of the page is decoration.
A metaphor that always works
You go to a fancy office building. The front desk asks for your ID. You hand it over. They check the photo, scan it, hand you a visitor badge.
That is authentication. They proved who you are.
Now you walk to the elevator and try to press 22, the executive floor. The elevator beeps and refuses. Your badge does not unlock floor 22. It unlocks floor 4 (where you have a meeting) and the cafeteria.
That is authorisation. The system decided what you are allowed to do.
You can absolutely have one without the other. A legitimate visitor (well-authenticated) can still be denied the executive floor (not authorised). An imposter who somehow obtained a stolen badge (improperly authenticated) might still be authorised for whatever that badge unlocks. The two checks happen at different moments and answer different questions.
In Dashify
Every API request goes through both checks, in this order.
If a request fails the authentication check, the API returns 401 Unauthorized — "I don't know who you are." If it passes authentication but fails authorisation, the API returns 403 Forbidden — "I know who you are, but you cannot do this."
The two status codes mean different things and the API is careful never to mix them up. A 401 invites the browser to redirect to the login page. A 403 invites the platform to display "you don't have access to this." Confusing them confuses users.
The flow inside Dashify
Authentication in Dashify is the session-cookie + RBAC stack we have been building up to. Authorisation is the three-tier RBAC system, covered in detail in the Security section. In short:
- A user has a role (SuperAdmin, OrgAdmin, or one of several user roles).
- The role has a list of permissions ("can create projects," "can edit invoices," "can manage users").
- The route handler declares the permission it requires.
- Before the handler runs, a middleware checks: does the user's role include this permission?
If yes, the handler runs. If no, 403.
Why split the two?
You might wonder why we don't just bundle "who you are" and "what you can do" into one check. The reason is maintenance.
Authentication rarely changes. The cookie is valid or it isn't.
Authorisation changes constantly. New features get new permissions. A new role gets added. A package upgrade unlocks a new menu. Permissions need to be configurable per tenant, per role, sometimes per user.
Keeping the two separated means we can evolve the authorisation layer freely without touching authentication, and vice versa. They are concerns that should not be tangled.
The third quiet sibling — packages
There is a third gate sitting alongside authentication and authorisation in Dashify: package gating. Even if you are authenticated and your role permits an action, the action might be unavailable because your tenant's subscription package does not include that feature.
Three checks, in order:
- Authenticated — yes/no, returns 401 if no.
- Package includes this menu/feature — yes/no, returns 403 (with redirect to /upgrade) if no.
- Role permits this action — yes/no, returns 403 if no.
All three have to pass for the handler to run. The Security section's RBAC page expands on this.
Common mistakes
A few patterns we explicitly avoid because they confuse the two concepts.
- Hiding a button on the client and assuming the server is safe. The client is a hint, not a security boundary. Every authorisation check has to live on the server too.
- Returning data the user is not authorised to see, but greying it out in the UI. That data is already in the response — they can read it with browser dev tools. If they cannot have it, the server should not send it.
- Returning 401 when we mean 403. If a logged-in user hits a forbidden endpoint and gets 401, the browser tries to refresh their session, fails, redirects to login, and the user thinks their session expired. Confusing.
- Returning 403 when we mean 401. If an unauthenticated user gets 403, the browser does not redirect to login. The user sees a wall.
Key takeaways
- Authentication = who you are. Authorisation = what you can do.
- The two checks happen at different moments and answer different questions.
- Failed authentication returns 401; failed authorisation returns 403.
- Dashify also gates by package — three checks total before any privileged endpoint runs.
- Never bundle the two; never trust the client to enforce them.