Learning path · Level 11 · Tutorial 4

Distinguish Authentication from Authorization

Separate sign-in status from resource permissions, identify ineffective client-only access checks, and choose appropriate interface behavior when an API refuses access.

  • Level: Intermediate
  • Duration: 15 min
  • 7 steps
Start tutorial Back to the path
Distinguish Authentication from Authorization

What you will go through

  1. Separate Identity, Permission, and Presentation Separate authentication, authorization, and interface presentation through Project Desk examples. 2 min
  2. Locate the Real Access Boundary Identify why browser-side route and control restrictions cannot enforce access to protected resources. 2 min
  3. Recognize Untrusted Access Claims Recognize that browser-supplied identifiers and claims can select or describe a request but cannot prove permission. 2 min
  4. Specify Checks for Each Resource and Action Determine the trusted server-side checks required before Project Desk returns protected project data or applies an update. 3 min
  5. Respond Appropriately to 401 and 403 Choose accurate sign-in-required or access-denied feedback for representative API refusals without exposing protected details or misreporting a refused update. 2 min
  6. Explore Local Interface Branches Build and inspect a small browser-only Project Desk simulation, then explain why its fixtures demonstrate interface presentation rather than secure access control. 3 min
  7. Review a Complete Access Decision Audit Project Desk access decisions by separating Browser presentation from Server/API authentication and authorization. 2 min

What you will learn

  • Classify an application requirement as authentication, authorization, or interface presentation.
  • Explain why changing a route parameter or bypassing a hidden control must not grant access.
  • Identify the server-enforced permission checks needed for a protected read or write.
  • Choose appropriate sign-in or access-denied feedback for representative 401 and 403 responses.

Before you start

  • Build Accessible Client-Side Routes with React Router
  • Represent Detail Views and Filters in the URL
  • Fetch and Validate JSON Responses
  • Send JSON Data with HTTP Requests
  • Protect Sensitive Data at the Browser Boundary

Step 1 of 7

Separate Identity, Permission, and Presentation

Separate authentication, authorization, and interface presentation through Project Desk examples.

Name the responsibility

Three separate questions

Project Desk separates three different jobs:

  • Authentication establishes the identity associated with a request. Sign in is an action; signed in is the resulting state the interface may represent.
  • Authorization decides whether that identity may perform a specific action on a specific resource.
  • Interface presentation decides what the browser displays: controls, routes, and messages.

These jobs are related, but they are not interchangeable. A signed-in user is not automatically allowed to read every project or update every project.

Different jobs, connected flow

A diagram separates Browser interface presentation from a Server/API permission decision. A request connects them, while authentication identifies Avery and authorization evaluates an update to Project 101.

The browser can represent signed-in status and available controls; authentication and authorization answer different questions about a request.

Tip

Keep the questions distinct

A browser can show that a user is signed in, but that display is interface presentation. It is not itself proof that a particular request is allowed.

Think in this order:

  1. Who is associated with the request? Authentication.
  2. May that identity perform this action on this project? Authorization.
  3. What should the browser show? Interface presentation.

Apply the policy to a request

Project Desk policy

Project Desk has two fictional users and owner-specific projects. The policy applies to a particular user, project, and action—not merely to whether someone is signed in.

Identity, resource, and action

Both roles can read their own project. Only an editor can update their own project. Neither role grants access to another user's project.

A permission decision needs all three parts: identity, target resource, and requested action.
UserRoleOwn projectRead own projectUpdate own project
Avery (u-1)editor101AllowedAllowed
Blair (u-2)viewer102AllowedNot allowed

Example

Same user, different responsibilities

Compare these requirements:

  • “Establish that the request is associated with Blair.” → authentication
  • “Decide whether Blair may update project 102.” → authorization
  • “Do not display Edit when the interface has no edit permission hint.” → interface presentation

For example, Avery may be signed in and still not be allowed to read Blair’s project 102. The identity is known; the requested resource is simply not permitted for that identity.

Practice: classify Project Desk requirements

Classify the requirement

Match each Project Desk requirement to its category.

Tap an item and then its matching pair.

Step 2 of 7

Locate the Real Access Boundary

Identify why browser-side route and control restrictions cannot enforce access to protected resources.

Find the decision point

The boundary is not the route

A route guard and conditional controls are interface presentation: they can guide a person away from /projects/101 or omit an Edit button. That is useful behavior, but it happens in the Browser, a user-controlled environment.

The protected resource is not protected merely because the route or control is hidden. The Server/API must make its own authorization decision before it returns protected data or accepts a change. Changing what the browser displays must not change that decision.

Where an access decision must happen

A diagram shows route and Edit-control presentation in the Browser, while a decision gate in Server/API sits before protected project data and an update action.

Browser controls can guide the interface. The Server/API must decide access before a response or change crosses the boundary.

Why browser-only restrictions fail

Helpful interface behavior is not enforcement

Consider Project Desk. A browser can redirect someone away from a project route, and it can hide or disable Edit when its local permissions.canEdit hint is false. Those choices improve navigation and reduce misleading actions.

But a person can alter browser state, enter a route directly, or send a request without using the visible control. Therefore, a hidden Edit control does not stop an independent request such as PATCH /api/projects/101. An altered interface must never turn a refused request into an allowed one.

Warning

Do not hide data after delivery

Post-download filtering is too late. If the API sends protected project data to the browser and the interface hides some fields afterward, that data has already crossed the boundary. Browser code, developer tools, or altered rendering can inspect what was delivered.

To prevent disclosure, the Server/API must refuse access before returning protected data. To prevent an unwanted change, it must refuse before applying the change.

Example

Keep the useful part

A route guard can still be valuable: it can keep a signed-out person from landing on a confusing detail screen, or avoid showing an Edit control that the interface does not expect them to use. Treat those as interface presentation. They complement—rather than replace—the Server/API access decision.

Check the boundary

Choose the real protection

Which design actually blocks unauthorized access before protected data is disclosed or a project change is made?

Step 3 of 7

Recognize Untrusted Access Claims

Recognize that browser-supplied identifiers and claims can select or describe a request but cannot prove permission.

Target selection is browser-controlled

A target is not a permission

A route parameter or API resource identifier selects a target; it does not prove that the requester may use that target.

For example, /projects/102 and GET /api/projects/102 identify Project 102. The identifier is syntactically valid, but that only means it has a usable format. It does not establish that Avery is permitted to read Blair’s project.

Treat values the browser can send or change as inputs, not as permission evidence.

Selecting a record versus proving access

A Browser request selects project 102, while the Server/API holds a separate stored record whose ownerId is u-2.

The request names a target. It does not supply trustworthy proof that the requester may access that target.

Different inputs, same trust limit

Claims are not authority

Changing the target is not the only untrusted access claim. A browser can also send a role, a user ID, an owner ID, or any payload field it chooses.

These values can be useful for interface presentation, but they cannot override the trusted authorization context or the resource information held by the Server/API. A caller cannot make a project their own merely by submitting a different ownerId, and cannot gain editor ability by submitting a different role.

Browser values can be changed

This browser-side fixture may help decide which control to display. Its values must not be treated as proof by a Server/API.

javascript
const currentUser = { id: "u-1", role: "editor" };
const projectId = "102";
const submittedOwnerId = "u-1";
const claimedRole = "editor";

const updatePayload = {
  ownerId: submittedOwnerId,
  role: claimedRole,
  name: "Updated project name"
};

Example

In this example, projectId chooses a target, while submittedOwnerId and claimedRole are caller-supplied claims. Their different purposes do not make either one authoritative permission evidence.

Practice: identify the claim

Classify the access claims

Match each browser-supplied value to what it attempts to describe.

Tap an item and then its matching pair.

Apply the distinction

Explain the trust boundary

A Project Desk browser displays Avery and sends PATCH /api/projects/102. The request is changed to include "role": "editor" and "ownerId": "u-1" in its JSON payload.

In 2–4 sentences, explain what the project ID selects, what the role and owner ID claim, and why changing these values must not grant Avery update access.

Write at least 120 characters (0/120).

Step 4 of 7

Specify Checks for Each Resource and Action

Determine the trusted server-side checks required before Project Desk returns protected project data or applies an update.

Make each request a server decision

Use trusted context and stored records

Every protected request needs a decision at the Server/API. The server establishes a trusted authentication context for the request; it does not treat a browser-supplied user ID, role, or owner claim as proof.

The requested project ID selects a record to resolve. The server then uses that record’s stored ownerId, together with the trusted identity, role, and requested action, for authorization. This must happen before protected data is returned or a change is applied.

Where the access decision belongs

A diagram shows a request crossing from Browser to Server/API, where trusted identity, the stored project owner, and the requested action feed an authorization decision before an allow or deny response returns.

The browser can request a target, but the Server/API makes the access decision from trusted context and stored resource data.

Apply ownership and action together

Read and update are different actions

Project Desk applies ownership and action rules separately for every request. A prior allowed read is not permission for a later update: GET /api/projects/102 and PATCH /api/projects/102 require distinct authorization decisions.

Project Desk permission matrix

The fixed policy below is evaluated against the project record’s stored ownerId and the trusted user identity and role.

Allowed outcomes under the fixed policy
Trusted userTarget projectReadUpdate
Avery (editor)101, owned by AveryAllowedAllowed
Avery (editor)102, owned by BlairDeniedDenied
Blair (viewer)102, owned by BlairAllowedDenied
Blair (viewer)101, owned by AveryDeniedDenied

Sequence the required checks

Order a protected decision

Arrange the server-side dependencies for one protected request.

  1. Resolve the requested project and read its stored ownerId.
  2. Only then return protected data or apply the change.
  3. Evaluate ownership, role, and the requested action.
  4. Establish a trusted identity for the request.

Check a complete access decision

Predict outcomes and required checks

Choose the complete server decision plan for these representative requests: Avery makes GET /api/projects/101; Avery makes PATCH /api/projects/102; Blair makes GET /api/projects/102; Blair makes PATCH /api/projects/102.

Step 5 of 7

Respond Appropriately to 401 and 403

Choose accurate sign-in-required or access-denied feedback for representative API refusals without exposing protected details or misreporting a refused update.

Read the response as an access signal

Interpret the access outcome

The API response is a signal for the interface, but its meaning comes from the API’s documented contract.

In this tutorial’s representative cases, 401 means valid authentication is missing or was not accepted. Its historical HTTP label, “Unauthorized,” does not mean that a signed-in person was evaluated and lacked a resource permission.

A representative 403 means the Server/API understood the request but refuses access. In the signed-in examples, authentication succeeded but authorization failed: the identity lacks permission for that resource or action.

Two different refusal states

A Browser-to-Server/API diagram contrasting a 401 response that leads to Sign in required with a 403 response that leads to Access denied.

Both outcomes stop the requested operation, but they call for different interface guidance.

Representative response handling

Use these as representative interface branches; a real API may document different details or additional response fields.

Do not infer more than the documented API contract provides.
ResponseRepresentative meaningInterface stateSafe next step
401Valid authentication is missing or not acceptedSign in requiredShow “Sign in to continue.” and offer Sign in
403The request is understood but access is refusedAccess deniedShow “You do not have permission to do that.” and offer safe navigation

Present a useful recovery path

Make refusal states safe and honest

Keep protected details out of a blocked read view. If a request to load a project is refused, replace any stale project content from that view with the relevant access state rather than leaving old details visible.

For a refused update, do not show a saved confirmation and do not retry the refusal indefinitely. A 403 for an update does not automatically mean that a separately authorized read must disappear: read permission and update permission remain separate decisions.

Select the appropriate feedback

Use a documented response status to select presentation. This branch does not make an access decision; the Server/API already made it.

javascript
function getAccessFeedback(responseStatus) {
  if (responseStatus === 401) {
    return {
      heading: "Sign in required",
      message: "Sign in to continue.",
      action: "Sign in"
    };
  }

  if (responseStatus === 403) {
    return {
      heading: "Access denied",
      message: "You do not have permission to do that.",
      action: "Back to projects"
    };
  }

  return null;
}

Example

Apply the state to reads and writes

Blocked read: If GET /api/projects/101 receives a representative 403, show the Access denied state, the permission message, and safe navigation. Do not leave project details in that blocked view.

Refused update: If PATCH /api/projects/101 receives a representative 403, do not report that the project was saved. Show the Access denied state instead. If the person is separately allowed to read the project, its existing read view can remain; the refused write is not a reason to invent a broader access loss.

Practice: match outcome to interface behavior

Choose the correct refusal response

Match each representative API outcome to the appropriate interface message and recovery action.

Tap an item and then its matching pair.

Step 6 of 7

Explore Local Interface Branches

Build and inspect a small browser-only Project Desk simulation, then explain why its fixtures demonstrate interface presentation rather than secure access control.

Frame the exercise

What the local simulation shows

This local exercise lets you switch among four interface presentation branches in Project Desk. The single file contains browser-only fixtures for identity, permission hints, an allowed project response, and a simulated API outcome.

It is useful for seeing what a browser should display after an outcome. It does not establish authentication or enforce authorization: there is no protected API, network request, or real sign-in in this exercise.

A presentation branch is not an access decision

Diagram showing four browser-only interface branches inside the Browser and a separate Server/API boundary that would make real access decisions.

The local fixture selector changes only Browser presentation. A real Server/API would decide access before returning protected content.

Warning

Important limitation

The page must display this exact notice: UI simulation—not an access-control system.

The refused fixtures deliberately contain no project object or protected project fields, and the renderer clears previously displayed project content before each branch. That makes the simulated refused response and rendered view accurate.

It still provides no security: every fixture in this standalone file is browser-controlled. Changing a fixture can demonstrate a different interface branch; it cannot grant access to a real project or prove that authorization is secure.

Create the page

Build the file, part 1

Create a new file named access-demo.html. Paste this first block into it. Leave the <script> element open: the next blocks continue the same file.

1. Page structure

Paste this first into access-demo.html.

html
<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Project Desk access demo</title>
  <style>
    body { font-family: system-ui, sans-serif; margin: 2rem; max-width: 42rem; }
    .panel { border: 1px solid #9ca3af; border-radius: 8px; padding: 1rem; margin-top: 1rem; }
    #notice { color: #7c2d12; font-weight: 700; }
    button { padding: 0.5rem 0.8rem; }
  </style>
</head>
<body>
  <main>
    <h1>Project Desk</h1>
    <p id="notice">UI simulation—not an access-control system.</p>

    <label for="caseSelect">Fixture case</label>
    <select id="caseSelect">
      <option value="signedOut">Signed out</option>
      <option value="denied">Signed in, denied</option>
      <option value="viewOnly">Allowed to read</option>
      <option value="editAllowed">Allowed to read and edit</option>
    </select>

    <section class="panel" aria-live="polite">
      <h2 id="stateTitle"></h2>
      <p id="stateMessage"></p>
      <div id="projectContent" hidden>
        <p id="projectName"></p>
        <button id="editButton" type="button" hidden>Edit project</button>
      </div>
    </section>
  </main>

  <script>

Finish and inspect the branches

2. Add browser-only fixtures

Paste this directly after the first block, inside its open <script> element. Notice that the two refused cases have no project property.

javascript
const fixtureCases = {
  signedOut: {
    currentUser: null,
    permissions: { canView: false, canEdit: false },
    responseStatus: 401
  },
  denied: {
    currentUser: { id: "u-2", name: "Blair", role: "viewer" },
    permissions: { canView: false, canEdit: false },
    responseStatus: 403
  },
  viewOnly: {
    currentUser: { id: "u-2", name: "Blair", role: "viewer" },
    project: { id: "102", ownerId: "u-2", name: "Research notes" },
    permissions: { canView: true, canEdit: false },
    responseStatus: 200
  },
  editAllowed: {
    currentUser: { id: "u-1", name: "Avery", role: "editor" },
    project: { id: "101", ownerId: "u-1", name: "Website refresh" },
    permissions: { canView: true, canEdit: true },
    responseStatus: 200
  }
};

const caseSelect = document.querySelector("#caseSelect");
const stateTitle = document.querySelector("#stateTitle");
const stateMessage = document.querySelector("#stateMessage");
const projectContent = document.querySelector("#projectContent");
const projectName = document.querySelector("#projectName");
const editButton = document.querySelector("#editButton");

3. Render each branch safely in the simulation

Paste this final block after the fixtures. Save the file; this block closes the script and document.

javascript
function renderCase() {
  const fixture = fixtureCases[caseSelect.value];
  const { currentUser, permissions, responseStatus } = fixture;

  projectName.textContent = "";
  projectContent.hidden = true;
  editButton.hidden = true;

  if (responseStatus === 401) {
    stateTitle.textContent = "Sign in required";
    stateMessage.textContent = "Sign in to continue.";
  } else if (responseStatus === 403) {
    stateTitle.textContent = "Access denied";
    stateMessage.textContent = "You do not have permission to do that.";
  } else if (!permissions.canView) {
    stateTitle.textContent = "Access denied";
    stateMessage.textContent = "You do not have permission to do that.";
  } else {
    const { project } = fixture;
    stateTitle.textContent = "Project available";
    stateMessage.textContent = `${currentUser.name} can view this project.`;
    projectName.textContent = project.name;
    projectContent.hidden = false;
    editButton.hidden = !permissions.canEdit;
  }
}

caseSelect.addEventListener("change", renderCase);
renderCase();
  </script>
</body>
</html>
Expected output
Signed out
Heading: Sign in required
Message: Sign in to continue.
Project content: hidden
Edit control: hidden

Signed in, denied
Heading: Access denied
Message: You do not have permission to do that.
Project content: hidden
Edit control: hidden

Allowed to read
Heading: Project available
Message: Blair can view this project.
Project: Research notes
Edit control: hidden

Allowed to read and edit
Heading: Project available
Message: Avery can view this project.
Project: Website refresh
Edit control: visible

This is the expected browser display after selecting each fixture case. The initial selection is Signed out; the display changes when you select another case.

Run and inspect

Open access-demo.html in your browser and change Fixture case. The refused simulated responses have no project field, and renderCase() first clears the old project name and hides its container. Therefore, switching from an allowed case to a refused case leaves no project details in the rendered view.

The allowed cases demonstrate presentation hints: permissions.canEdit controls whether the Edit control is visible. These values remain local fixtures, not authorization evidence.

Expected interface states

Four Project Desk interface states: sign-in required and access denied show no project content; Blair's allowed read shows Research notes without Edit; Avery's allowed read shows Website refresh with Edit visible.

Compare the exact headings and messages, then check whether project content and the Edit control are present in each state.

Apply and explain

Complete the presentation logic

Complete the simulated outcome and Edit-control branches.

javascript
if (responseStatus === ) {
  stateTitle.textContent = "Sign in required";
} else if (responseStatus === ) {
  stateTitle.textContent = "Access denied";
} else if (permissions.canView) {
  editButton.hidden = !permissions.;
}

Interpret your local result

After saving your local file, select Signed out and then Allowed to read. In 2–4 sentences, report the exact message in the signed-out state, whether the Edit control is visible in the read-only state, and why editing fixtures with browser tools cannot demonstrate a secure access-control system.

Write at least 120 characters (0/120).

Step 7 of 7

Review a Complete Access Decision

Audit Project Desk access decisions by separating Browser presentation from Server/API authentication and authorization.

One audit, four decisions

One audit, four decisions

A complete access review asks four questions for every request: who is making it, which project is targeted, which action is requested, and what may the interface show afterward?

In Project Desk, the browser can guide a person with a route or a hidden control. That is interface presentation. The Server/API must establish identity through authentication and decide the specific project action through authorization.

Use the response status and permitted data together: a refusal must not include protected project details or claim that a refused update was saved.

Project Desk audit

Use this compact audit table to connect each situation to its authoritative decision.

The Server/API, not the Browser, makes the access decision for each request.
SituationPrimary categoryServer/API decisionBrowser outcome
Signed out → GET 101authenticationNo accepted identity → 401; no project dataSign in required
Blair → GET 101authorizationStored ownerId differs → 403; no project dataAccess denied
Blair → PATCH 102authorizationViewer cannot update → 403; no saved changeAccess denied
Hidden Edit controlinterface presentationEndpoint still checks every requestDisplay is not permission

Where the decision belongs

A diagram separates Browser from Server/API. The browser sends a project request, while the server checks trusted identity, stored ownership, and permission before returning content or a refusal.

A route and Edit control shape interface presentation; they do not replace Server/API authentication and authorization.

Spot the broken boundary

Spot the broken boundary

Blair is signed in as a viewer. On /projects/102, the Browser hides Edit because permissions.canEdit is false. Blair changes local Browser code to show Edit and sends PATCH /api/projects/102.

Which correction protects the update?

Final access review

Final access review

Audit this draft design for Project Desk:

“/projects/:projectId redirects signed-out visitors. The Browser hides Edit when permissions.canEdit is false. For updates, the API trusts the ownerId and role sent in the request body.”

Use these cases: a signed-out request for GET /api/projects/101; Blair (u-2, viewer) requesting project 101, which belongs to Avery (u-1); and Blair sending PATCH /api/projects/102, which Blair owns.

In 5–8 sentences, identify the client-only flaw and explain why bypassing a route or control cannot grant access. Classify the responsibilities as authentication, authorization, or interface presentation. Then specify the trusted Server/API checks for the read and update, and give the suitable status plus interface label and message for each refused case.

Write at least 350 characters (0/350).

Transfer the rule

Summary

Transfer the rule

The reusable access rule is simple: interface presentation communicates access, while the Server/API enforces access for the requested resource and action.

A route parameter selects a target. A hidden control guides the interface. Neither establishes identity nor grants permission. For each protected read or write, the Server/API uses trusted authentication context, stored resource information, and the requested action to make an authorization decision.

  • Authentication establishes the identity associated with a request.
  • Authorization decides whether that identity may perform an action on a specific resource.
  • Interface presentation can guide navigation and feedback, but cannot enforce access.
  • A refused 401 request needs Sign in required feedback; a refused 403 request needs Access denied feedback.
  • Protected data and successful-save messaging must not appear after a refused decision.

Tutorial complete

Congratulations! You completed: Distinguish Authentication from Authorization

You can now separate authentication, authorization, and interface presentation—and explain why the Server/API must enforce every protected resource action.

Download the App now to have access to + 5000 free courses, exercises, certificates and lots of content without paying anything!

  • 100% free online courses from start to finish

    Thousands of online courses in video, ebooks and audiobooks.

  • More than 60 thousand free exercises

    To test your knowledge during online courses

  • Valid free Digital Certificate with QR Code

    Generated directly from your cell phone's photo gallery and sent to your email

Cursa app on the ebook screen, the video course screen and the course exercises screen, plus the course completion certificate