Search
30 results for “oauth”
Search results
OAuth 2.0 vs OpenID Connect
OAuth 2.0 handles authorization and OpenID Connect adds authentication on top. What each actually does, and why the distinction matters.
What is an app registration in Entra ID, and why do workloads need one?
An app registration represents an application's identity in Entra ID, giving it a client ID and the ability to authenticate, either as itself (via a client secret or certificate, for service-to-service calls) or on behalf of a signed-in user (via OAuth 2.0/OpenID Connect flows). Workloads need one because Entra ID authentication and authorization apply uniformly to both humans and applications, a background service calling an API needs its own verifiable identity the same way a person does, and an app registration (often combined with a managed identity to avoid handling secrets directly) is how that identity is established.
What problem does a tool like Poetry or uv solve that pip and venv alone do not?
pip installs packages and venv creates isolated environments, but neither one manages the two together as a single reproducible workflow, nor do they resolve and lock a full dependency tree (including transitive dependencies) automatically. Tools like Poetry and uv combine environment creation, dependency resolution, lockfile generation, and package building into one workflow, similar to how npm or cargo work in other ecosystems, removing the manual, error-prone process of keeping a requirements file, a lockfile, and an environment all consistent with each other by hand.
Why would an organization use multiple AWS accounts instead of one account holding all resources?
Separate accounts per environment (production, staging, development) or per team give a hard isolation boundary that a single account with tags or naming conventions cannot: a mistake or compromised credential in a development account cannot reach production resources at all, rather than merely being restricted by IAM policy within the same account. It also gives cleaner cost attribution (billing rolls up per account), independent service quotas, and a natural blast-radius limit for security incidents. AWS Organizations, and patterns built on top of it like a landing zone, exist specifically to make many accounts manageable, centralized billing, centralized logging, and org-wide SCPs, without losing that isolation.
What are the five stages of the browser rendering pipeline, and which ones does a change to a property like width actually have to go through?
The pipeline runs JavaScript, Style calculation, Layout, Paint, and Composite, in that order. Changing a property that affects geometry, `width`, `height`, `position`, forces the browser through every stage: layout has to be recalculated (since the element's size or position changed), then paint (since pixels changed), then composite. That full path is why layout-affecting properties are the most expensive to animate, every frame re-runs the whole pipeline, not just a cheap final step.
Why would a hash join beat a nested loop join for two large, unindexed tables, but lose to a nested loop join when one table is tiny?
A nested loop join's cost scales with (outer rows) × (cost of an inner-side lookup per row), so with two large unindexed tables, the inner-side scan is expensive and gets repeated for every single outer row, making the total cost grow multiplicatively. A hash join instead pays a roughly one-time cost to build a hash table from one side, then does a cheap lookup per row from the other side, additive rather than multiplicative, which wins decisively at scale. But when one table is tiny, the nested loop's "repeat the inner scan per outer row" cost is trivial regardless, and it avoids the hash table's build overhead entirely, so the simpler algorithm wins for small inputs specifically.
Terraform Azure Tutorial: How to Create Resource Groups, VNets, Subnets, NSGs, and VMs Step‑by‑Step IaC
Terraform on Azure: Building a Real-World Infrastructure from Scratch.
A client sends a payment request, the network times out before a response arrives, and the client retries with the same idempotency key. What actually happens on the server?
If the original request already completed (successfully or even with an error like a 500) before the retry arrives, the server returns the exact same result it returned (or would have returned) the first time, the same status code and response body, without re-executing the underlying operation, so the customer isn't charged twice just because the client never saw the first response. This is the entire point of an idempotency key: it lets a client safely retry an operation whose actual outcome it's genuinely uncertain about (did the first request even reach the server? did it complete before the timeout?) without that retry risking a duplicate side effect.
During a live incident, what does journalctl -f -u myservice -p err do, and why combine those specific options?
`-f` follows the journal in real time, printing new entries as they're appended, `-u myservice` scopes that stream to just the one unit under investigation, and `-p err` filters to only entries at the "err" priority or more severe (more important), suppressing informational noise. Combined, this gives a live, scoped, severity-filtered view of exactly one service's serious problems as they happen, rather than watching an unfiltered firehose of every unit's routine log output and trying to manually spot the relevant failure.
How does a load balancer detect and handle an unhealthy backend server?
Via health checks, periodic requests (a lightweight HTTP endpoint like /healthz, or a TCP connection check) sent to each backend on an interval. A server that fails a configurable number of consecutive checks is marked unhealthy and removed from the rotation; it is added back only after passing a configurable number of consecutive successful checks, which avoids flapping a server in and out of rotation on a single transient failure.
Why does a chunk like "The company's revenue grew by 3% over the previous quarter" cause a retrieval failure even if it's embedded correctly?
That sentence is only meaningful with context the isolated chunk doesn't carry, which company, which quarter, information that likely lived in a heading or preceding paragraph that didn't survive the chunking boundary. Embedded on its own, the chunk's vector represents a generic, context-free statement about revenue growth, which means it won't be retrieved reliably for a query about "ACME Corp Q2 2023 earnings" even though it's exactly the right chunk, because nothing in its embedding actually encodes that it's about ACME Corp or Q2 2023 at all.
What is the "first rule of ARIA," and why does a native <button> beat a <div role="button"> even though both can be made accessible?"
The W3C's own first rule of ARIA use is direct: if a native HTML element or attribute already provides the semantics and behavior you need, use it instead of re-purposing a different element with ARIA. A native `<button>` comes with keyboard interaction (Enter/Space activates it, Tab reaches it), focus management, and correct semantics built into the browser for free. A `<div role="button">` requires manually replicating every one of those behaviors with JavaScript and additional ARIA attributes, tabindex, keydown handlers for both Enter and Space, and it is easy to miss an edge case a real button never had in the first place. ARIA can make a div accessible in theory; a native element already is, with less code and less risk.
What do LCP, INP, and CLS each measure, and why are all three needed instead of one overall "speed" number?
LCP (Largest Contentful Paint) measures loading performance, specifically how quickly the largest visible element renders, "good" is 2.5 seconds or less. INP (Interaction to Next Paint) measures interactivity/responsiveness, the delay between a user interaction and the browser's next visual response, "good" is 200 milliseconds or less. CLS (Cumulative Layout Shift) measures visual stability, how much content unexpectedly shifts around during the page's lifecycle, "good" is a score of 0.1 or less. A single overall number couldn't distinguish a page that loads fast but jumps around from one that's stable but slow to interact with, three separate metrics are needed because loading, interactivity, and stability are genuinely different failure modes.
What is the difference between authentication and authorization in a cloud IAM context?
Authentication answers "who is making this request", verifying an identity via credentials, a token, or a federated login. Authorization answers "is this identity allowed to do this specific action on this specific resource", evaluated after authentication succeeds, by checking the identity's attached policies against the requested action. A request can be perfectly authenticated (the caller genuinely is who they claim) and still be denied, because authorization is a separate check against what that identity is actually permitted to do.
What does box-sizing: border-box actually change about how width and height are calculated?
With the default `content-box`, `width` applies only to the content area, so padding and border are added on top, a 200px-wide box with 20px padding and a 5px border renders at 250px total. `border-box` makes `width` include content, padding, and border together, so that same 200px `width` stays 200px total regardless of padding or border, the content area itself shrinks to make room instead. This is why most modern projects apply `box-sizing: border-box` globally, it makes an element's declared width predictable and stable as padding/border change, instead of recalculating the total size by hand every time.
Why does a naive recursive Fibonacci function run in exponential time, and how does memoization fix that specifically?
Naive recursive `fib(n) = fib(n-1) + fib(n-2)` recomputes the exact same subproblem enormous numbers of times, `fib(n-2)` gets computed once directly and once again inside the `fib(n-1)` call, and this duplication compounds recursively, producing roughly 2^n total calls. Memoization caches each `fib(k)` result the first time it's computed, so every subsequent call with the same `k` becomes an O(1) cache lookup instead of a full recursive recomputation, collapsing the total distinct work down to O(n), one computation per distinct subproblem instead of an exponential number of repeated ones.
Why does a word count poorly estimate how many tokens a prompt will use?
A token is a commonly-occurring sequence of characters the model was trained on, not a word, common short words are often a single token, while a longer or less common word can split into several tokens ("tokenization" might become " token" plus "ization"). As a rough rule of thumb, one token is about 4 characters or 0.75 words in English, but that ratio shifts with vocabulary, punctuation, and especially non-English text, so a word count is only ever an approximation, not the actual unit the model's context window and pricing are measured in.
Why is using a mutable object (like a list) as a default argument value a common bug in Python?
Default argument values are evaluated exactly once, when the function is defined, not on every call, so a mutable default like `def f(items=[])` creates one list object that is shared across every call that doesn't explicitly pass its own `items`. Appending to it in one call leaves those items present the next time the function is called with the default, which looks like inexplicable state leaking between unrelated calls. The fix is defaulting to `None` and creating a new list inside the function body when `items is None`, so every call that needs the default gets its own fresh object.
Why would a system use a sliding window rate limiter instead of a token bucket, and what problem does it fix?
A naive fixed window (say, "100 requests per minute, resetting on the minute") allows a client to send 100 requests in the last second of one window and another 100 in the first second of the next, 200 requests in a two-second span despite the stated 100/minute limit, an artifact of the window boundary rather than actual demand. A sliding window rate limiter instead evaluates the limit over a continuously moving time range rather than fixed, discrete buckets, which avoids that boundary-doubling effect at the cost of typically more state to track (timestamps of recent requests, not just a single counter) compared to a token bucket's simpler accumulator model.
Given the risk of hitting a recursion limit, when would you rewrite a recursive algorithm iteratively, and what does that actually trade away?
Rewrite iteratively when the recursion depth scales with input size in a way that could plausibly exceed the platform's real stack capacity, deep tree traversals, recursive descent over large or adversarial inputs, anything where "how deep" isn't bounded by a small constant. The trade is code clarity: many recursive algorithms (tree traversal, divide-and-conquer, backtracking) read far more naturally as recursion, mirroring the problem's own recursive structure, and converting them to an explicit-stack iterative version, while removing the depth risk entirely, usually costs some of that direct correspondence between code and problem structure.
What is the difference between a client tool and a server tool, and why does that distinction matter for what your application has to do?
A client tool executes in your own application, the model only returns the structured request to call it; your code is responsible for actually running it (hitting your database, calling your API) and returning the result. A server tool, like a web search or code execution tool a provider offers, executes on the provider's own infrastructure, so your application sees the final result directly without ever writing execution code for it. The distinction determines how much you have to build: every client tool needs your own execution and error-handling code, while server tools need none, just declaring them in the request.
What does an EC2 Auto Scaling Group actually manage, and why does the scaling metric choice matter?
An Auto Scaling Group keeps a fleet of EC2 instances at a desired size, launching or terminating instances automatically based on configured scaling policies, and replacing instances that fail health checks, so nobody is manually adding or removing servers as load changes. The scaling metric determines whether that automation actually tracks the real bottleneck: scaling purely on CPU utilization looks like "autoscaling is working" on a dashboard while a memory-bound or queue-depth-bound workload keeps falling behind, because the metric driving the scaling policy never reflected the actual constraint. Choosing a metric (or combination of metrics, including custom CloudWatch metrics) that matches the workload's real bottleneck is what makes the automation actually correct rather than just present.
Why does an O(n log n) sort beat an O(n^2) sort for large inputs, even if the O(n^2) one is faster on small inputs?
Constant factors can make an O(n^2) algorithm faster for small n, Big O only describes the asymptotic trend, not the exact runtime. But growth rates diverge fast: at n = 1,000,000, n log n is about 20 million operations while n^2 is a trillion. Past a crossover point the asymptotically better algorithm always wins, which is why production sort implementations (like Timsort) still often special-case small arrays with a simpler O(n^2) sort under the hood.
Why does binary search require the input to already be sorted, and what actually happens if you run it on unsorted data?
Binary search's core logic is comparing the target against a midpoint and eliminating the entire half that can't possibly contain it, an elimination step that's only valid if elements are ordered, so everything below the midpoint really is smaller and everything above really is larger. Run it on unsorted data and there's no error or exception, the algorithm has no way to detect the invariant is broken, it just keeps halving the search space based on comparisons that no longer imply anything real, and returns an insertion point or "not found" result that has no actual relationship to whether or where the target exists in the list.
Why does a naive `hash(key) % N` scheme for distributing keys across N servers fall apart the moment a server is added or removed?
With plain modulo hashing, the server a key maps to depends directly on the current value of N, since almost every key's `hash(key) % N` result changes the instant N changes to N-1 or N+1, even though the underlying hash values themselves didn't change at all. That means adding or removing a single server can remap the overwhelming majority of keys to different servers simultaneously, which for a cache means a massive wave of cache misses, and for a sharded store means a massive, unnecessary data-migration event, triggered by a change to just one server out of many.
Why does publishing a port with -p 8080:80 not automatically make the container reachable from other containers?
-p (or --publish) maps a port on the Docker host to a port inside the container, specifically for reaching the container from outside the Docker network, from the host machine or the internet. Other containers on the same user-defined network do not need that mapping at all; they can reach the container directly on its internal port via the container's name and internal port, because they share the internal bridge network. Publishing a port is about host-to-container access, not container-to-container access.
What does NIST's own definition of dynamic programming actually say the technique does, and what problem does it solve?
NIST's Dictionary of Algorithms and Data Structures defines dynamic programming as an algorithmic technique to "solve an optimization problem by caching subproblem solutions (memoization) rather than recomputing them." The problem it solves is redundant recomputation: when a naive recursive solution calls itself with the same subproblem arguments repeatedly (matrix-chain multiplication, longest common subsequence, and similar problems are the examples NIST gives), that same subproblem gets solved from scratch every single time it recurs, and caching the first result lets every later occurrence be a lookup instead of a full recomputation.
For the same graph, why might you choose DFS over BFS even though BFS finds shortest paths and DFS doesn't?
Shortest-path guarantees aren't always the goal, DFS is a natural fit for exhaustively exploring all possibilities along one path before trying another (backtracking problems, detecting cycles, topological sorting, finding connected components), where the actual requirement is "visit everything reachable" or "explore this branch fully before trying the next," not "find the closest thing first." DFS via recursion is also often simpler to implement for these problems, at the cost of consuming call-stack depth proportional to how deep the graph goes, which matters for very deep or very large graphs where an iterative approach (or BFS) avoids the recursion-depth risk entirely.
Why does Linux split user information across /etc/passwd and /etc/shadow instead of keeping everything, including the password hash, in one file?
/etc/passwd has to be world-readable, ordinary tools and commands need to map UIDs to usernames and look up home directories or login shells for every user on the system. If password hashes lived there too, every local user could copy them out and run an offline cracking attempt. /etc/shadow holds the actual encrypted password (and related aging data) and is readable only by root, while /etc/passwd keeps a placeholder character (commonly `x`) in the password field, preserving the UID-lookup functionality everything else depends on without exposing anything crackable.
What does the kernel actually check when deciding whether a process can access a file, the username or the UID?
The UID. A username is a human-readable label that /etc/passwd maps to a numeric UID, but every permission check, ownership comparison, and process credential the kernel deals with operates on that number, root is UID 0 specifically, not "whichever account is named root." This is why two different usernames can be given identical privileges by sharing UID 0, and why renaming an account changes nothing about what it's allowed to do, only the numeric UID does.