Skip to main content
Madhukar
All Articles

Securing Apps: Password Hashing, RBAC, OAuth, and OpenID Connect

July 16, 20265 min read
SecurityOauthBackendAuthentication
Securing Apps: Password Hashing, RBAC, OAuth, and OpenID Connect

How does a website know who you are?

You type your email and password into a login form. A second later, you’re in — your dashboard, your orders, your messages, all correctly yours and nobody else’s.

That single moment hides an enormous amount of engineering: how your password was stored without ever being readable, how the server decided you’re really you, and how it then decided what you specifically are allowed to see and do.

This guide builds that picture one layer at a time — starting with the humble password, and ending at the systems powering “Sign in with Google” and enterprise Single Sign-On.

1. Why Application Security Matters

Common security risks in web applications

Most breaches don’t come from exotic zero-day exploits — they come from ordinary, well-documented mistakes:

  • Storing passwords in plain text or with weak hashing
  • Trusting client-side checks instead of verifying on the server
  • Giving every logged-in user the same level of access
  • Leaving admin routes reachable without proper checks
  • Tokens or sessions that never expire

Why authentication and authorization are different problems

It’s tempting to treat “logged in” as one single concept, but it’s actually two separate questions layered on top of each other:

  • Who are you? (authentication)
  • What are you allowed to do? (authorization)

Getting the first one right doesn’t automatically get you the second — a common source of real vulnerabilities is a correctly authenticated user reaching an action they were never authorized for.

The cost of insecure systems

Beyond the obvious — stolen data, drained accounts — insecure systems cost user trust, regulatory penalties, and engineering time spent firefighting instead of building. A single leaked password database can compromise users on other services too, since password reuse across sites is extremely common.

Real-world examples of security failures

Security history is full of avoidable failures: massive credential leaks caused by unsalted or unhashed password storage, authorization bugs that let ordinary users reach admin endpoints just by guessing a URL, and OAuth misconfigurations that let attackers impersonate legitimate apps. Almost every major one traces back to skipping one of the fundamentals covered below.

2. Password Hashing and Storage

Why passwords should never be stored in plain text

If a database is ever leaked — and eventually, somewhere, one will be — plain-text passwords hand attackers everything instantly: every account, on your app and on any other site where a user reused that same password.

What hashing is

Hashing is a one-way mathematical transformation. You put a password in; you get a fixed-length, seemingly random string out. Critically, it’s designed to be effectively impossible to reverse — you can’t take the hash and recover the original password.

"mySecret123" → hash() → "$2b$12$KIXQ7z9..."

How bcrypt works

bcrypt is a hashing algorithm purpose-built for passwords — and deliberately slow. That’s a feature, not a flaw: fast hashing algorithms (like those built for file integrity checks) let attackers try billions of password guesses per second. bcrypt’s deliberate slowness, controlled by a “cost factor,” makes large-scale guessing attacks impractically slow, while a single legitimate login still takes a fraction of a second.

Salt and hashing concepts

A salt is random data added to a password before hashing. Without it, two users with the identical password (“password123”) would produce the identical hash — letting attackers use precomputed lookup tables (rainbow tables) to crack many accounts at once. With a unique salt per user, the same password produces a completely different hash for every account, defeating that shortcut entirely. bcrypt generates and embeds this salt automatically.

Password verification process

The server never “decrypts” a stored hash to check a login — hashing isn’t reversible. Instead, it re-hashes the password the user just typed, using the same salt, and compares the two hashes:

Best practices for password storage

  • Never store plain-text passwords — ever, not even temporarily in logs
  • Use a purpose-built algorithm (bcrypt, scrypt, or Argon2) — never a general-purpose hash like MD5 or SHA-1 alone
  • Let the library handle salting automatically rather than rolling your own
  • Enforce reasonable password strength rules without becoming so strict that users resort to insecure workarounds
  • Rate-limit login attempts to slow down brute-force guessing

3. Authentication vs Authorization

What authentication means

Authentication answers “who are you?” It’s the process of proving identity — typically via a password, a one-time code, biometrics, or a valid session/token.

What authorization means

Authorization answers “what are you allowed to do?” It happens after authentication and determines which resources, pages, or actions a verified identity can access.

Why applications need both

Authentication without authorization means every logged-in user could do anything — including things meant only for admins. Authorization without authentication is meaningless, because you’d be granting permissions to an unverified identity. They’re two locks in sequence, not one.

Examples from everyday applications

4. Role-Based Access Control (RBAC)

What RBAC is

RBAC assigns permissions to roles, not directly to individual users. Users are then assigned one or more roles. This indirection is the whole point — it turns “manage 10,000 individual permission sets” into “manage 5 well-defined roles.”

Users, roles, and permissions

  • User — an individual account (e.g., aarav@example.com)
  • Role — a named collection of permissions (e.g., Editor, Admin)
  • Permission — a specific allowed action (e.g., delete_post, view_billing)

Designing role hierarchies

Roles are often layered so higher roles inherit lower ones’ permissions rather than duplicating them — an Admin implicitly gets everything a Moderator and User can do, plus more.

Common RBAC patterns

  • Flat roles — a fixed, small set of roles (simple apps)
  • Hierarchical roles — roles inherit from lower roles (most SaaS products)
  • Scoped roles — a role applies only within a specific team, project, or organization (multi-tenant products)

Admin vs User vs Moderator examples

  • User — can view content, edit their own profile, place orders
  • Moderator — everything a User can do, plus remove flagged content, ban abusive accounts
  • Admin — everything a Moderator can do, plus manage billing, roles, and system settings

Scaling permissions in large applications

As applications grow, hardcoding if (user.role === "admin") checks throughout the codebase becomes unmanageable and error-prone. Mature systems centralize permission checks — often as a single reusable function or middleware — so every route enforces access rules the same, auditable way, instead of each developer reinventing the check slightly differently.

5. OAuth 2.0 Explained

What problem OAuth solves

Imagine a photo-printing app that needs access to your Google Photos. The naive solution — typing your Google password directly into the printing app — is a serious security risk: that third-party app now holds full, unrestricted credentials to your entire Google account, forever, with no way to limit or revoke just that access.

Why sharing passwords is dangerous

A shared password grants everything, indefinitely, with no scope and no easy revocation. OAuth 2.0 exists specifically to eliminate this — letting an app get limited, revocable access to specific resources, without ever seeing your password at all.

Authorization flow overview

OAuth defines a small set of roles that interact in a defined sequence:

  • Resource Owner — you, the user who owns the data
  • Client Application — the app requesting access (the photo printer)
  • Authorization Server — the service that authenticates you and issues permission (Google’s login system)
  • Resource Server — where the actual protected data lives (Google Photos’ API)

Access tokens

Instead of a password, the client application receives an access token — a limited-scope, time-bound credential. It might grant “read-only access to your photos for one hour” and nothing more — no password exposure, no unlimited access, and it can be revoked at any time without changing your actual password.

Real-world examples such as “Login with Google”

“Continue with Google” / “Continue with GitHub” buttons are OAuth in action — the app never sees your Google password. It receives a scoped token proving you approved this specific app for this specific access, which you can revoke anytime from your Google account settings without changing your password at all.

6. OpenID Connect (OIDC)

What OIDC is

Here’s a subtlety that trips a lot of people up: OAuth was designed for authorization, not authentication. A valid access token proves an app was granted access to something — it doesn’t strictly prove who the user is. OpenID Connect (OIDC) is a thin identity layer built directly on top of OAuth 2.0 to close that gap properly.

How it extends OAuth

OIDC adds a standardized way to answer “who is this user?” alongside OAuth’s existing “what can this app access?” — using the same flow, roles, and infrastructure, with one key addition.

Authentication vs authorization (again, at the protocol level)

  • OAuth 2.0 → issues an Access Token → authorization (“what can this app do?”)
  • OpenID Connect → additionally issues an ID Token → authentication (“who is this user?”)

ID tokens

The ID Token is a compact, signed token (a JWT) containing verified identity claims — typically a unique user ID, email, and name — issued by the authorization server and cryptographically verifiable by the client without an extra round trip.

User identity verification

Because the ID Token is signed by a trusted authorization server, the client application can verify a user’s identity cryptographically — without maintaining its own password database or authentication system at all.

Modern login systems

This is precisely the mechanism behind nearly every “Sign in with Google / Apple / Microsoft” button you see today — OIDC handles proving identity, while OAuth (running underneath it) handles any actual data access the app also needs.

7. Modern Authentication Architecture

Traditional login systems

The classic model: a form, a password, a server-side session or token, stored and verified against your own database. Simple, fully self-contained — but it means you are fully responsible for password storage security, breach response, and every edge case (password resets, account recovery, and so on).

Social login systems

Delegating authentication to Google, GitHub, or Apple via OAuth/OIDC removes password-storage responsibility from your app entirely and lets users skip creating yet another password — at the cost of depending on a third-party provider’s availability and policies.

Enterprise authentication

Larger organizations typically centralize identity through protocols like SAML or OIDC, connected to an internal identity provider (Okta, Azure AD, Google Workspace) — so IT can manage access to every company tool from one place, and instantly revoke access company-wide the moment someone leaves.

Single Sign-On (SSO)

SSO lets a user authenticate once and gain access to multiple, independent applications without logging in separately to each. It’s built on the same authorization-server pattern as OAuth/OIDC — just pointed at many client applications instead of one.

Authentication in modern SaaS products

Most production SaaS today blends these patterns: email/password or social login for individual signup, SSO for enterprise customers, and RBAC underneath all of it to determine what each authenticated identity can actually do once inside.

8. Security Best Practices

Strong password policies

Encourage length over complexity — a long passphrase is often both more secure and easier to remember than a short string of forced symbols. Check new passwords against known-breached password lists where possible.

Multi-factor authentication

MFA requires a second proof of identity beyond a password — a time-based code, a push notification, or a hardware key. It’s one of the single highest-leverage defenses available, since it neutralizes most attacks that rely on a stolen or guessed password alone.

Token expiration

Access tokens and sessions should expire — short-lived tokens dramatically limit the damage window if one is ever leaked. Pair short-lived access tokens with longer-lived, securely stored refresh tokens for a good balance of security and user convenience.

Secure storage of credentials

Never log passwords or tokens. Store secrets (API keys, database credentials) in environment variables or a secrets manager — never committed directly into source code.

Principle of least privilege

Every user, role, and service should have the minimum access required to do its job — nothing more “just in case.” This single principle limits the blast radius of almost any single security failure.

Protecting sensitive routes

Every sensitive route needs both checks, every time: is this request authenticated, and is this specific identity authorized for this specific action? Relying on hiding a URL (“security through obscurity”) is not a substitute for an actual server-side check.

Final Takeaway

Every layer in this guide exists to answer one of two questions, precisely and safely: “Who are you?” and “What are you allowed to do?” Password hashing protects the first check’s foundation. Authentication and authorization split the problem cleanly. RBAC scales authorization across large teams. OAuth lets apps cooperate without ever trading passwords. OIDC completes OAuth with real identity. None of it is exotic — it’s a set of well-understood layers, stacked deliberately, each solving the specific gap the layer before it left open.

Frequently Asked Questions

Is OAuth the same as OpenID Connect?

>No. OAuth 2.0 is an authorization protocol — it controls access to resources. OpenID Connect is an identity layer built on top of OAuth that adds proper authentication, via a signed ID Token.

Why can’t I just encrypt passwords instead of hashing them?

> Encryption is reversible by design — whoever holds the key can recover the original password, which is itself a liability if that key is ever exposed. Hashing is intentionally one-way, so even the application itself can’t retrieve the original password, only verify a guess against it.

Is RBAC enough for large applications?

> For many applications, yes. Very large or highly granular systems sometimes layer on Attribute-Based Access Control (ABAC) or permission-based systems alongside RBAC for finer-grained control, but RBAC remains the standard starting point.

Do I need OAuth if I’m not using social login?

> Not necessarily. A simple app with its own username/password system doesn’t require OAuth. OAuth becomes relevant the moment your app needs to access another service’s resources on a user’s behalf, or wants to offload authentication to a trusted third party.

Originally published by Mr Madhukar

Read the complete article on Medium with full formatting & reader responses.