Web Development using JavaScript/React

Chapter 9
Data Integration, APIs, and Authentication

Bachelors Program in IT
Web Development using JavaScript/React   •   Bachelor

Data Integration, APIs, and Authentication

Introduction

Modern web applications rarely operate in isolation. A React application may obtain product information from a commerce service, user profiles from an identity provider, payments from a financial platform, and analytics from a separate data pipeline. Data integration is therefore a central web-development capability rather than an optional enhancement.

This chapter examines how browser-based applications communicate with external services and how those services protect data. It focuses on REST and introductory GraphQL, asynchronous data loading, caching, synchronization, errors, pagination, optimistic updates, authentication, authorization, tokens, sessions, and role-based access control. The emphasis is practical, but the underlying principles are applicable to professional software architecture.

A useful distinction is that authentication answers “Who is the user?”, whereas authorization answers “What is that user allowed to do?” A secure application must address both questions, and it must enforce permissions on the server even when the user interface also hides unauthorized controls.

Learning Objectives

By the end of this chapter, students should be able to:

  1. Explain the purpose and structure of APIs in web applications.
  2. Compare REST and GraphQL and select an appropriate approach for a given problem.
  3. Integrate asynchronous services into React components and hooks.
  4. Design strategies for caching, synchronization, pagination, error handling, and optimistic updates.
  5. Distinguish authentication, authorization, sessions, and tokens.
  6. Explain common token-based authentication flows and their security risks.
  7. Implement role-aware interfaces while preserving server-side access control.
  8. Evaluate data-integration designs in terms of reliability, security, usability, and maintainability.

1. APIs as Contracts Between Systems

An API, or application programming interface, is a defined mechanism through which one software system requests operations or data from another. In web development, APIs commonly use HTTP and exchange JSON representations.

An API contract normally specifies:

  • available endpoints or operations;
  • required parameters and request bodies;
  • response structures;
  • authentication requirements;
  • error formats;
  • pagination and filtering rules; and
  • relevant HTTP status codes.

For example, a REST service might expose:

OperationHTTP methodExample resourceTypical meaning
Read collectionGET/api/productsRetrieve products
Read itemGET/api/products/42Retrieve product 42
CreatePOST/api/productsCreate a product
Replace or updatePUT/PATCH/api/products/42Modify a product
DeleteDELETE/api/products/42Remove a product

HTTP methods communicate intent. GET should be safe and generally does not change server state. POST commonly creates a resource or triggers an operation. PUT traditionally replaces a resource, while PATCH applies a partial modification. DELETE removes a resource. Actual behavior must follow the documented API contract.

A response contains a status code, headers, and possibly a body. Common codes include 200 OK, 201 Created, 204 No Content, 400 Bad Request, 401 Unauthorized when authentication is absent or invalid, 403 Forbidden when identity is known but permission is insufficient, 404 Not Found, 409 Conflict, 422 Unprocessable Content, and 500 Internal Server Error.

The distinction between 401 and 403 is particularly important: a client may respond to 401 by requesting authentication, but it should not assume that authenticating will resolve a 403 permission failure.

2. REST and GraphQL

REST

REST-style APIs organize information as resources identified by URLs. A client requests representations of those resources, often in JSON. REST benefits from familiar HTTP semantics, mature tooling, browser compatibility, and straightforward caching.

A request might be:

const response = await fetch('/api/products?category=books');

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

const products = await response.json();

The fetch function rejects for network-level failures, such as a DNS problem, but it does not automatically reject for HTTP errors such as 404 or 500. Applications must therefore inspect response.ok or response.status.

REST can produce two common data-shaping problems. Under-fetching occurs when a client needs several requests to obtain related data. Over-fetching occurs when an endpoint returns substantially more fields than the view needs. These problems can be addressed through specialized endpoints, query parameters, or a different API design.

GraphQL

GraphQL exposes a typed schema and usually a single endpoint. The client specifies the fields it requires in a query:

query ProductDetails($id: ID!) {
  product(id: $id) {
    id
    name
    price
    reviews {
      rating
      comment
    }
  }
}

The server validates the query against its schema and returns a response shaped around the requested fields. GraphQL can reduce over-fetching and combine related data in one request. It is especially useful when multiple clients need different views of the same domain model.

However, GraphQL does not automatically solve performance or security problems. Poorly designed queries can request deeply nested data and consume substantial server resources. Services should use query-depth limits, complexity limits, pagination, authorization checks, and appropriate resolver design. GraphQL responses may return HTTP status 200 while placing operation errors in an errors array, so clients must inspect both the transport response and the GraphQL payload.

ConcernRESTGraphQL
Main abstractionResources and URLsTyped schema and operations
Data shapePrimarily server-definedClient-selected fields
CachingOften compatible with HTTP cachingUsually requires client or persisted-query strategies
Learning curveFamiliar HTTP modelSchema, queries, mutations, resolvers
Typical riskMany requests or inconsistent endpointsExpensive or overly broad queries

Neither approach is universally superior. REST is often appropriate for stable resource-oriented services and public HTTP APIs. GraphQL is valuable when clients have diverse data requirements or relationships are central to the user experience.

3. Integrating Asynchronous Data in React

A React component should represent at least the major states of an asynchronous operation: loading, success, and failure. A useful state model is:

const [state, setState] = useState({
  status: 'idle',
  data: null,
  error: null
});

A basic effect-based implementation is:

useEffect(() => {
  const controller = new AbortController();

  async function loadProducts() {
    setState({ status: 'loading', data: null, error: null });
    try {
      const response = await fetch('/api/products', {
        signal: controller.signal
      });
      if (!response.ok) throw new Error(`HTTP ${response.status}`);
      const data = await response.json();
      setState({ status: 'success', data, error: null });
    } catch (error) {
      if (error.name !== 'AbortError') {
        setState({ status: 'error', data: null, error });
      }
    }
  }

  loadProducts();
  return () => controller.abort();
}, []);

The AbortController prevents an obsolete request from updating a component after unmounting or after its inputs have changed. In production, data-fetching libraries such as TanStack Query or SWR can provide caching, retries, deduplication, and synchronization, but developers must still understand the underlying lifecycle.

A robust integration separates concerns:

  • an API module handles HTTP requests and response parsing;
  • a data layer manages cache and synchronization;
  • components render states and collect user input; and
  • authorization logic determines whether an operation is allowed.

This separation improves testing and prevents components from becoming tightly coupled to URL construction and error interpretation.

4. Caching and Synchronization

A cache stores previously retrieved data so that later reads can be faster and impose less load on the service. A cache entry should be associated with a precise key. For example, product lists filtered by category and page must not share the same key as the unfiltered first page.

A conceptual cache key might be:

['products', { category: 'books', page: 2, limit: 20 }]

Caching introduces a consistency problem: cached data may become stale while the server changes. A common strategy is stale-while-revalidate. The interface immediately displays cached data, then requests a fresh version in the background. If the fresh response differs, the cache and user interface are updated.

Applications can also synchronize data through:

  • refetching when a window regains focus;
  • polling at a defined interval;
  • server-sent events or WebSockets for near-real-time updates;
  • invalidating related cache entries after a mutation; and
  • explicit refresh controls for users.

There is no universally correct freshness period. A dashboard displaying rapidly changing inventory may need frequent synchronization, whereas a reference page may tolerate stale data for several minutes. The decision should reflect business risk, network cost, and user expectations.

Caching must not expose private information. Cache scope, eviction, encryption requirements, and user identity changes must be considered. A cache shared between users is unsafe if it can return one user’s private response to another.

5. Errors, Retries, and Resilience

Errors should be classified rather than treated as one generic failure. Useful categories include:

  1. Validation errors: the submitted data is invalid.
  2. Authentication errors: credentials or tokens are missing or invalid.
  3. Authorization errors: the user lacks permission.
  4. Conflict errors: the requested change conflicts with current server state.
  5. Transient errors: a timeout or temporary service failure may succeed later.
  6. Permanent service errors: retrying is unlikely to help without correction.

Retry policies require care. Retrying a failed GET may be safe in many situations, but retrying a POST can create duplicate resources unless the API supports an idempotency key. Exponential backoff increases the delay between attempts and reduces pressure on an overloaded service. A bounded policy should define maximum attempts, maximum delay, and which errors qualify for retry.

The user interface should communicate actionable information. “Unable to save changes. Try again” is more useful than displaying a raw stack trace, while detailed technical information should be logged securely for developers. Error messages must not reveal secrets, internal database details, or sensitive personal information.

6. Pagination and Large Collections

Returning thousands of records in one response harms performance and usability. Pagination divides a collection into manageable portions.

Offset pagination uses a page number and page size:

GET /api/orders?page=3&limit=25

It is easy to understand, but records inserted or deleted between requests can cause duplicates or omissions. Cursor pagination uses a server-generated cursor representing a position in a stable ordering:

GET /api/orders?limit=25&after=eyJpZCI6MTAw...

Cursor pagination is often more reliable for changing datasets, particularly for infinite scrolling. The cursor should be treated as opaque; clients should not decode or construct it unless the API explicitly permits this.

A pagination response may contain:

{
  "items": [{ "id": 101, "total": 42 }],
  "nextCursor": "opaque-value"
}

The interface should prevent duplicate loading, indicate whether more data exists, preserve ordering, and handle errors during subsequent page requests. Infinite scrolling should also remain accessible; a conventional “Load more” control may be preferable for keyboard and screen-reader users.

7. Optimistic Updates and Synchronization Conflicts

An optimistic update changes the interface immediately, assuming that the server operation will succeed. For example, when a user marks a task complete, the task can appear complete before the response returns. This improves perceived responsiveness but requires rollback if the server rejects the operation.

A safe optimistic process is:

  1. Record the previous cached state.
  2. Apply the proposed local change.
  3. Send the mutation to the server.
  4. On success, reconcile with the authoritative response.
  5. On failure, restore the previous state and explain the failure.
const previous = queryClient.getQueryData(['tasks']);

queryClient.setQueryData(['tasks'], tasks =>
  tasks.map(task => task.id === id ? { ...task, done: true } : task)
);

try {
  await updateTask(id, { done: true });
  await queryClient.invalidateQueries({ queryKey: ['tasks'] });
} catch (error) {
  queryClient.setQueryData(['tasks'], previous);
  throw error;
}

This example is schematic and assumes that the mutation is appropriate for optimistic treatment. Optimistic updates are less suitable for operations with complex side effects, irreversible financial consequences, or high conflict probability.

When two users edit the same record, the client may receive a conflict. Applications can use version numbers, timestamps, ETags, or server-side conflict policies. A version-based model might reject an update if the client’s version no longer matches the server’s current version. Automatically choosing “last write wins” is simple but can silently discard valuable work.

8. Authentication Models

Authentication establishes a user’s identity. Common models include passwords, multifactor authentication, social login, passkeys, and enterprise identity protocols such as OAuth 2.0 and OpenID Connect.

Passwords should never be stored directly. A server stores a salted, computationally expensive password hash generated by a specialized password-hashing algorithm such as Argon2id, scrypt, or bcrypt. Password hashing is different from encryption: encryption is reversible with a key, while a password hash is designed to be computationally difficult to reverse.

Multifactor authentication combines different factors, such as:

  • knowledge: a password or PIN;
  • possession: a security key or authenticator device; and
  • inherence: a biometric characteristic.

Two passwords are not two independent factors. Strong multifactor authentication substantially reduces the impact of a stolen password, although recovery procedures remain a significant security concern.

Sessions

In a session-based design, the server creates a session record after successful login and sends the browser a session identifier, commonly in an HttpOnly, Secure, and appropriately configured SameSite cookie. The browser automatically sends the cookie on matching requests, and the server retrieves the associated session.

Advantages include straightforward revocation and centralized control. Risks include session theft and cross-site request forgery (CSRF). CSRF defenses may include appropriate SameSite settings, anti-CSRF tokens, and origin checking. Session identifiers should be rotated after login or privilege changes and invalidated at logout or expiration.

Tokens

A token is a credential presented by a client. A bearer token grants access to whoever possesses it, so leakage is serious. JSON Web Tokens (JWTs) commonly contain claims such as subject, issuer, audience, and expiration. A signed JWT provides integrity: the recipient can detect unauthorized modification. It does not automatically provide confidentiality; unless encrypted, its contents can be read by anyone who obtains it.

The server must validate the signature, issuer, audience, expiration, and appropriate algorithm. It must not trust claims merely because they are present in a decoded token. Short-lived access tokens reduce exposure, while refresh tokens can obtain new access tokens. Refresh-token rotation and reuse detection improve security.

For browser applications, storing long-lived tokens in localStorage makes them accessible to JavaScript and therefore more exposed during an XSS attack. A common architecture keeps refresh credentials in protected cookies and uses short-lived access credentials, but the exact design depends on the identity provider and threat model. No storage choice eliminates the need for input protection, content-security policy, dependency management, and secure server validation.

OAuth 2.0 is an authorization framework for delegated access; OpenID Connect adds an identity layer on top of OAuth 2.0. Developers should use well-tested provider libraries rather than implementing protocol details from memory. The authorization-code flow with Proof Key for Code Exchange (PKCE) is a contemporary choice for public clients because it helps prevent interception of an authorization code.

9. Authorization and Role-Based Access Control

Authorization determines whether an authenticated principal may perform an action on a resource. Role-based access control (RBAC) assigns permissions to roles, then assigns roles to users.

For example:

RoleExample permissions
ViewerRead published reports
EditorCreate and modify reports
ManagerApprove reports and manage team content
AdministratorConfigure the system and manage access

A React application may conditionally render a button:

{currentUser.permissions.includes('report:approve') && (
  <button onClick={approveReport}>Approve</button>
)}

This improves usability, but it is not a security boundary. A malicious user can call the API directly. Every protected operation must be authorized by the server using the authenticated identity, resource ownership, role, and other policy conditions.

RBAC can become too coarse for complex organizations. Attribute-based access control (ABAC) evaluates attributes such as department, location, resource owner, time, or data classification. A policy might permit a manager to edit reports only within the manager’s department. The principle of least privilege requires granting only the permissions necessary for a legitimate task.

Authorization should be tested both positively and negatively. Tests should verify that permitted users succeed and that unauthorized users receive a correct denial without learning confidential details.

10. Security and Governance Considerations

Data integration creates technical and organizational responsibilities. Applications should:

  • use HTTPS in production;
  • validate and constrain input on the server;
  • avoid exposing secrets in frontend bundles;
  • configure CORS narrowly rather than allowing arbitrary origins;
  • protect against XSS, CSRF, injection, and insecure direct object references;
  • apply rate limits and abuse monitoring;
  • minimize collection and retention of personal data;
  • define audit records for sensitive actions; and
  • provide appropriate deletion, correction, and access processes.

Privacy regulations may impose requirements concerning consent, purpose limitation, data minimization, retention, and user rights. A frontend should not collect information merely because an API makes it technically available. Logs, analytics, and error-monitoring systems can themselves contain personal or security-sensitive data.

AI services introduce additional integration concerns. Prompts and retrieved records may contain confidential information, and model outputs may be inaccurate or biased. Access controls must apply before data is sent to an AI service, and generated results should be treated as untrusted until validated. AI does not replace authorization, input validation, or human accountability.

11. Applied Case: Campus Equipment-Loan Portal

Background

This illustrative case concerns a university portal through which students reserve cameras and laboratory equipment. The system has a React frontend, a REST API, an identity provider, and an administrative dashboard.

Problem

The initial implementation loaded all equipment in one request, stored a long-lived access token in browser storage, and allowed the interface to hide administrative buttons without enforcing the same rules on the API. Users sometimes saw outdated availability and occasionally created conflicting reservations.

Analysis

The portal requires three distinct policy decisions. First, a student may view available equipment and create reservations for permitted items. Second, an administrator may add equipment and approve maintenance status. Third, the server must prevent overlapping reservations even when two clients submit requests nearly simultaneously.

The system also needs a clear data strategy. Equipment lists should be paginated and cached briefly. Availability should be refreshed when a reservation is created and when the page regains focus. A reservation operation should not rely exclusively on a client-side optimistic assumption because the server is authoritative for conflicts.

Approach and Solution

The portal uses OpenID Connect with an authorization-code flow and PKCE. Short-lived access credentials are used for API calls, while refresh handling follows the identity provider’s protected mechanism. The API validates the token and derives permissions from server-controlled identity data.

The equipment endpoint supports cursor pagination and returns an opaque next cursor. The React data layer caches pages by filter and cursor. Creating a reservation may optimistically mark a button as “Submitting,” but the equipment availability is confirmed by the server. If the server returns 409 Conflict, the client refreshes the relevant item and explains that another reservation was accepted first.

Administrative operations require a server-side permission such as equipment:manage. The frontend hides management controls for ordinary users, but the API independently rejects unauthorized requests. Audit events record equipment changes and reservation approvals without recording unnecessary credentials or sensitive data.

Outcome

The revised portal reduces redundant requests, presents fresher availability information, and prevents frontend-only authorization bypasses. Cursor pagination improves behavior as the equipment inventory grows. Conflict responses make competing reservations understandable instead of silently overwriting one another.

Learning Points

The case demonstrates that data integration is not merely a matter of calling fetch. Reliability depends on lifecycle management, cache invalidation, conflict handling, and clear server contracts. Security depends on protecting credentials and enforcing permissions at the API boundary. User experience improves when technical states such as loading, conflict, and retry are represented honestly.

12. Best-Practice Design Checklist

Before releasing an integrated React feature, ask:

  1. Is the API contract documented and versioned?
  2. Are loading, empty, success, error, and retry states represented?
  3. Can obsolete requests be cancelled or ignored safely?
  4. Are cache keys complete and is stale data acceptable for this feature?
  5. Does pagination preserve ordering and accessibility?
  6. Are mutations idempotent where retries may occur?
  7. If optimistic updates are used, is rollback defined?
  8. Are authentication credentials protected and appropriately short-lived?
  9. Does the server enforce every authorization decision?
  10. Are sensitive data, logs, and third-party integrations governed responsibly?

Chapter Summary

APIs provide contracts through which React applications communicate with external systems. REST organizes interactions around resources and HTTP methods, while GraphQL provides a typed schema through which clients select fields. Both require careful attention to validation, performance, errors, and security.

Reliable data integration models asynchronous states, cancels obsolete requests, uses deliberate caching, synchronizes stale data, handles pagination, and distinguishes transient failures from permanent errors. Optimistic updates can improve responsiveness but require rollback and reconciliation. Authentication establishes identity through sessions, tokens, or identity protocols; authorization determines permitted actions. Cookies, JWTs, OAuth 2.0, OpenID Connect, PKCE, password hashing, CSRF protection, and secure token handling each address different parts of the security problem. RBAC simplifies permission administration, while more complex systems may require attribute-based policies. Most importantly, interface restrictions are not security controls: authorization must be enforced by the server.

Key Terms

API: A defined interface through which software systems exchange operations or data.

REST: An HTTP-oriented architectural style that commonly represents resources through URLs and methods.

GraphQL: A typed query language and runtime in which clients request specified fields from a schema.

Endpoint: A network-accessible location and operation exposed by an API.

Cache: Stored data used to reduce latency and repeated requests.

Stale-while-revalidate: A strategy that displays cached data while obtaining a newer version in the background.

Pagination: Dividing a large collection into smaller responses.

Cursor pagination: Pagination based on an opaque position marker rather than a page number.

Optimistic update: A local interface change made before server confirmation.

Authentication: Verification of a user or system identity.

Authorization: Determination of whether an identity may perform an action.

Session: Server-managed state associated with a client credential.

Token: A credential presented to obtain access to a service or resource.

JWT: A signed, structured token format containing claims.

OAuth 2.0: An authorization framework for delegated access.

OpenID Connect: An identity protocol built on OAuth 2.0.

RBAC: Role-based access control, in which permissions are assigned through roles.

Least privilege: Granting only the access necessary for an authorized task.

CSRF: An attack that causes a browser to submit an unwanted authenticated request.

Idempotency: A property whereby repeating an operation has the same intended effect as performing it once.

Review Questions

Short Answer Questions

  1. What is the difference between a 401 response and a 403 response?
  2. Why must a fetch client inspect response.ok?
  3. What problem does cursor pagination address?
  4. Define authentication and authorization.
  5. Why is hiding a button in React insufficient for security?

Long Answer Questions

  1. Compare REST and GraphQL in terms of data shaping, caching, complexity, and suitable use cases.
  2. Explain how caching and synchronization affect the consistency of a React application.
  3. Describe a secure session-based authentication design, including cookie attributes and CSRF considerations.
  4. Explain the complete lifecycle of an optimistic update, including rollback and reconciliation.
  5. Discuss how RBAC, least privilege, and server-side policy enforcement work together.

Analytical / Application Questions

  1. A reservation application receives frequent 409 Conflict responses when users reserve the same item. Propose a client and server strategy for preserving data correctness while maintaining a good user experience.
  2. A team wants to store long-lived JWTs in localStorage because it is easy to implement. Evaluate the security risks and recommend a safer architecture.
  3. Design an API integration for a reporting dashboard with 10,000 records, slowly changing data, manager-only export functionality, and occasional service outages. Justify your choices concerning pagination, caching, errors, authentication, and authorization.

Multiple Choice Questions with Answers

Question 1

Which statement correctly distinguishes authentication from authorization?

A. Authentication determines identity; authorization determines permitted actions.

B. Authentication encrypts data; authorization compresses data.

C. Authentication paginates results; authorization caches results.

D. Authentication applies only to administrators; authorization applies only to students.

Correct Answer: A. Authentication determines identity; authorization determines permitted actions.

Question 2

What must a fetch-based client do because fetch does not automatically reject HTTP 404 responses?

A. Convert every response to GraphQL.

B. Inspect response.ok or response.status and handle the error.

C. Disable the browser cache.

D. Retry the request indefinitely.

Correct Answer: B. Inspect response.ok or response.status and handle the error.

Question 3

Which pagination approach is generally more suitable for a frequently changing collection and infinite scrolling?

A. A fixed page number without ordering.

B. Returning the entire collection each time.

C. Cursor pagination with a stable ordering.

D. Randomly selecting records for each request.

Correct Answer: C. Cursor pagination with a stable ordering.

Question 4

Why is an optimistic update normally paired with rollback logic?

A. The browser cannot display JSON without rollback.

B. The server may reject the mutation after the interface has changed.

C. Rollback is required to make GET requests idempotent.

D. Caching systems cannot store successful responses.

Correct Answer: B. The server may reject the mutation after the interface has changed.

Question 5

Which credential property is provided by a signed JWT but not automatically by signing alone?

A. Integrity against unauthorized modification.

B. Confidentiality of all claim contents.

C. Guaranteed authorization for every API.

D. Protection from token theft.

Correct Answer: A. Integrity against unauthorized modification.

Question 6

What is the primary security weakness of enforcing permissions only by hiding React buttons?

A. React cannot render buttons efficiently.

B. A user can call the API directly and bypass the interface.

C. Hidden buttons prevent HTTPS.

D. The technique causes cursor pagination to fail.

Correct Answer: B. A user can call the API directly and bypass the interface.

Question 7

Which HTTP status most commonly indicates that the request is authenticated but the user lacks permission?

A. 200

B. 201

C. 403

D. 404

Correct Answer: C. 403

Question 8

What is the main purpose of an AbortController in a React data-loading effect?

A. To encrypt the response body.

B. To cancel obsolete requests and avoid inappropriate updates.

C. To assign roles to users.

D. To convert REST into GraphQL.

Correct Answer: B. To cancel obsolete requests and avoid inappropriate updates.

Question 9

Which practice best supports least privilege?

A. Giving every authenticated user administrator access.

B. Granting only the permissions required for the user’s legitimate tasks.

C. Trusting role claims without validating the token.

D. Using one shared account for all staff.

Correct Answer: B. Granting only the permissions required for the user’s legitimate tasks.

Question 10

Why can retrying a POST request be dangerous when the API has no idempotency mechanism?

A. POST requests cannot contain JSON.

B. A retry may create duplicate side effects or resources.

C. POST requests are always unauthorized.

D. Retries disable server-side authorization.

Correct Answer: B. A retry may create duplicate side effects or resources.

Web Development using JavaScript/React
Chapter 9 of 14