AI 资讯
From Passwords to Token-based Authentication
Every authentication mechanism in use today emerged to address a specific set of constraints the previous one wasn't designed for. This article walks through that chain — not as a list of definitions, but as a sequence of problems and the constraints that shaped each solution. 1. The Problem With Sending Passwords Every Request The earliest widely used approach, HTTP Basic Authentication, is also the simplest to understand. The client sends the username and password, base64-encoded, on every single request: GET /api/data Authorization: Basic dXNlcjpwYXNzd29yZA== Base64 is not encryption — it's just a reversible encoding. Anyone who intercepts this header has the raw credentials. This approach has three structural problems. First, the password is transmitted on every request, which means every request is a new opportunity for it to leak — through logs, proxies, or a compromised network. Second, the server has to validate credentials against the database on every single call, since there's no concept of an established session; that's a database hit for every API request, which doesn't scale. Third, there's no way to limit what the credentials can do or for how long. The password grants full access until it's changed, and changing it is the only way to revoke access — there's no way to invalidate just one client's access without affecting every other client using the same password. 2. Sessions Try to Fix It, But Introduce New Problems The next evolution moved the credential check to a single moment: login. After verifying the password once, the server creates a session, stores it (in memory or a database), and gives the client a session ID, usually via a cookie. Every subsequent request just sends that ID, not the password. The user logs in by submitting their username and password. Browser ───────────────▶ Server Login Request The server validates the credentials. Server ── checks username/password ──▶ Database If the credentials are valid, the server creates a new se
AI 资讯
CVE-2026-8037: Critical RCE Vulnerability in Progress Kemp LoadMaster Requires Immediate Patching
Introduction: Unveiling the Critical Vulnerability The recently identified CVE-2026-8037 vulnerability in Progress Kemp LoadMaster represents a critical threat to enterprise infrastructure. This remote code execution (RCE) flaw, stemming from an uninitialized heap issue , enables pre-authentication exploitation, allowing attackers to bypass initial security barriers without valid credentials. The root cause lies in the failure to initialize dynamically allocated memory regions, creating an exploitable condition where untrusted input can corrupt critical data structures. Attackers leverage this memory corruption to redirect program execution to malicious payloads, achieving full system compromise—from data exfiltration to operational disruption. Technically, the vulnerability arises during the software’s handling of untrusted input. When memory chunks in the heap are allocated but not properly initialized, they retain residual data or undefined states. Attackers exploit this oversight by crafting inputs that overwrite function pointers or control-flow structures, hijacking the program’s execution path. The causal sequence is precise: uninitialized heap → memory corruption → arbitrary code execution → system compromise. The pre-authentication nature of the exploit exacerbates the risk, as attackers require no prior access to execute their payload, rendering perimeter defenses ineffective. The implications are severe for enterprises relying on Kemp LoadMaster for load balancing and application delivery. Unpatched systems are exposed to infiltration, data theft, and ransomware deployment. Beyond the technical failure, CVE-2026-8037 exposes systemic deficiencies: insufficient input validation in software design and inadequate security testing during development. Organizations further amplify risk through delayed patch management , creating a critical window of opportunity for attackers. Immediate remediation is imperative to prevent catastrophic breaches that could under
AI 资讯
Your OTP regex assumes six digits. Supabase magic links don't.
Sign-in worked flawlessly in dev. Then a real user pasted a real code and got "invalid format" — before the code ever reached Supabase. The credential was fine. My regex was wrong. Here's the one-line assumption that broke auth for every human who wasn't me. I run a Discord-native Company Brain. Teams /save docs and /ask grounded answers; access is gated by a magic-link claim that emails a one-time code. Standard GoTrue OTP flow. The client shows a box, you paste the code, the server verifies it. Boring — which is exactly what auth should be. The bug: a six-digit assumption in a validation guard The claim handler did a cheap client-side sanity check before calling verifyOtp : // The bug. Looks reasonable. Rejects every real code. const OTP = /^ \d{6} $/ ; function normalize ( input : string ): string { const code = input . trim (); if ( ! OTP . test ( code )) throw new Error ( " Enter the 6-digit code from your email. " ); return code ; } Every OTP tutorial uses \d{6} . Every code demo shows six digits. So I typed six digits into the test and it passed. In dev I was generating my own codes and never actually reading the email. Supabase's GoTrue emits an eight-digit code on this project. ^\d{6}$ rejects eight digits outright. The user's perfectly valid credential got thrown out by my own front door with a lie for an error message — "enter the 6-digit code" when the email plainly showed eight. Why it happens: OTP length is a setting, not a constant The length of a GoTrue email OTP is configurable — GOTRUE_MAILER_OTP_LENGTH (Dashboard → Authentication → Email). It defaults to six in many setups and to eight in others depending on when and how the project was provisioned. The number in the tutorial is that author's project setting , not a property of OTPs. Hardcoding 6 couples your client to a server config you don't control and might change. Bump the length for security later and every client silently starts rejecting valid codes. No error in your logs — the rejection
AI 资讯
How to Implement Biometric Authentication in a Flutter App (The Right Way)
In today's world, security is no longer optional - it's expected. Whether it's a fintech app, a fitness tracker, or an internal company tool, users want fast and secure access without the hassle of remembering passwords. That's exactly where biometric authentication comes in. In this guide, we'll walk through how we implement biometric authentication in a Flutter app , the practical approach we follow in production, and the common mistakes developers often make (and how to avoid them). Why Biometric Authentication? Before jumping into implementation, let's quickly understand why it matters: Faster login experience (no typing passwords) More secure than traditional authentication Native support across Android & iOS Better user trust and retention What We Use in Flutter To implement biometric authentication, we rely on: local_auth package (official Flutter plugin) Native biometric APIs under the hood (Face ID, Touch ID, Fingerprint) Step 1: Add Dependency dependencies : local_auth : ^3.0.1 Then run: flutter pub get Step 2: Platform Setup ✅ Android Setup Inside android/app/src/main/AndroidManifest.xml : <uses-permission android:name= "android.permission.USE_BIOMETRIC" /> Also ensure: <uses-feature android:name= "android.hardware.fingerprint" android:required= "false" /> ✅ iOS Setup Inside ios/Runner/Info.plist : <key> NSFaceIDUsageDescription </key> <string> We use Face ID to authenticate you securely </string> ⚠️ Without this, Face ID will NOT work and your app may crash. Step 3: Implement Biometric Logic Here's how we structure it in production: import 'package:flutter/foundation.dart' ; import 'package:local_auth/local_auth.dart' ; class BiometricService { final LocalAuthentication _auth = LocalAuthentication (); /// Check if device supports biometrics Future < bool > isBiometricAvailable () async { try { final bool canCheckBiometrics = await _auth . canCheckBiometrics ; final bool isDeviceSupported = await _auth . isDeviceSupported (); return canCheckBiometrics &&
AI 资讯
A Deactivated Admin Could Still Use Their Token. That's When Dual-Mode JWT Stopped Being About Speed.
What building cross-service RBAC taught me about the difference between a fast check and a correct one VaultPay is a wallet microservice I built on top of AuthShield. Previous parts: Part 1 is here: I Built AuthShield and Immediately Knew It Wasn't Enough Part 2 is here: The Silent Failure I Never Saw Coming: What VaultPay Taught Me About Consistency Under Failure Part 3 is here: I Started With a Blocklist. That Was the Wrong Instinct and VaultPay Taught Me Why. Part 4 is here: I Watched Money Move Twice From the Same Request. That's When I Understood Idempotency. Part 5 is here: I Almost Hashed a Document Number That Needed to Be Read Again When I designed JWT validation for VaultPay, the only thing I was optimising for was speed. Local verification, no network call, decode the token with the shared secret, read the claims, move on. Every request gets this. It's fast - no round trip to AuthShield, no added latency on the hot path. That felt like the obvious right answer for a system processing financial transactions, where every millisecond on the request path matters. Then I asked myself a question I hadn't thought through properly: what happens if an admin gets deactivated in AuthShield right now, this second, while they still have a valid token sitting in their browser? The answer, with pure local validation, is uncomfortable. Nothing happens. The token is still cryptographically valid. The signature checks out. The claims say role: admin . VaultPay has no way of knowing that AuthShield revoked this person's access thirty seconds ago, because VaultPay never asked AuthShield. It just trusted the token. That's the moment dual-mode validation stopped being a performance optimisation and became a correctness requirement. Two Services, No Shared Database VaultPay and AuthShield are separate microservices with separate databases. AuthShield owns user accounts, login, JWT issuance, and role management. VaultPay owns wallets, transactions, KYC, and admin operations on t
AI 资讯
MCP Server Auth: The API Is the Real Boundary
A single shared API key is fine right up until a second person uses it. intent-brain — the system, repo qmd-team-intent-kb , renamed to the intent-brain plugin v0.4.0 this day — is a team knowledge base. A Fastify HTTP API sits over a governed memory corpus. In front of that API is an MCP server named teamkb , so a teammate doesn't open a dashboard or learn an endpoint. They ask in Claude Code and get a cited answer back with qmd:// citations. That's the whole pitch: institutional memory you query in the same place you write code. Up to this day it authenticated with one shared TEAMKB_API_KEY . The shared key has two failures that only show up once the tool has more than one user. First, every request looks identical, so the audit log can't say who asked. Second, revoking one person means rotating the key for everyone — there's no per-person handle to drop. Both are structural, not bugs you patch. You fix them by giving each person their own credential. The work closed that gap with three things, in this order: per-user tokens (identity), a server-side write gate (authorization), and a per-read access log (audit). The through-line: the API is the real boundary. The MCP client-side tool gate is UX, not security. And the per-read access log stays separate from the governance audit trail — separate log, not no log. Identity: per-user tokens replace the shared key apps/api/src/auth/token-registry.ts . Each token resolves to a record: { actor, role } , where role is 'admin' | 'member' . The shared key's two failures both dissolve here — every request now carries an actor , and revoking one person is dropping one record, not a team-wide rotation. Tokens come from layered sources, in precedence order: explicit records → a TEAMKB_TOKENS JSON env → a TEAMKB_TOKENS_FILE (default ~/.teamkb/tokens.json ) → the legacy single TEAMKB_API_KEY , which becomes one admin token with actor "shared" for back-compat. Each entry is a bearer token resolved to an identity at request time. Ma
AI 资讯
Should Your App Adopt Passkeys?
Someone on your leadership team asked a reasonable question: should we adopt passkeys? You searched for answers and found implementation tutorials - WebAuthn server libraries, credential storage schemas, ceremony diagrams. They assume you've already decided. None of that helps you answer the question you were actually asked. This article is a decision guide. The question isn't how to implement passkey login. It's whether you should, when the timing makes sense, and for which users first. Implementation details matter eventually - but they don't belong at the front of the decision. You've seen Apple's demos and Google's Chrome nudges. Your security team may have sent a memo about phishing-resistant authentication. You know the term. What you don't have is a clear way to evaluate whether passkeys fit your product, your users, and your team's capacity to ship and support them. By the end of this article, you'll have scored your app against a readiness checklist, mapped show-stoppers that can block adoption, and drafted a one-page recommendation for leadership. Plain Terms: Passkeys, Passwords, and MFA Before scoring your app, you and stakeholders need to mean the same thing when you say "passkey", "password", and "MFA". Vendor decks use these loosely. A PM might say "passkeys replace passwords" while security means "phishing-resistant credentials". Both can be true. Passwords are shared secrets the user types; your server checks a hash. They leak via breaches and phishing sites. Users forget them, reuse them, and call support. MFA adds a second factor - app push, SMS, hardware key, or biometric. It cuts credential-stuffing and many phishing attacks, but adds friction, lost-device tickets, and cross-platform complexity. Passkeys are cryptographic key pairs on the user's device. The private key never leaves the device or synced passkey manager. Sign-in means unlocking with biometrics or a PIN; your server stores only the public key and verifies a signature. On web, the b
AI 资讯
GitHub ships a one-click self-revoke for users whose credentials just leaked
You forwarded the phishing email to the security channel about ninety seconds too late. The laptop is already cooperating with someone else. Your personal access token, the one you minted "just for that one script", is on its way to whatever Discord pays for stolen tokens this week. Now what? For users on GitHub Enterprise, what was previously a clickthrough checklist you complete while your hands shake is now one button. On June 24 the GitHub Changelog announced a self-service credential revocation flow under Settings, Credentials. From that view a user can see counts of every credential they have generated or authorized through SSO, then revoke or delete all of them in a single action. Personal access tokens, SSH keys, OAuth tokens, SSO authorizations: gone together. What actually shipped Containment used to be a manual scavenger hunt. PATs sat under Developer Settings. SSH keys lived one tab over. OAuth apps you forgot you authorized two years ago hid behind a different submenu. SSO was its own world. In practice that meant during an incident you forgot something, and the something you forgot was the credential the attacker actually wanted. The new view collapses that surface onto one screen. Counts on one side, a revoke-or-delete-everything action on the other. Whoever wrote it had clearly pictured the 3am screenshot: a user who has just been told to "rotate everything" and has no idea where "everything" lives. GitHub frames this as a complement to an earlier enterprise-owner capability that lets admins with the "Manage enterprise credentials" permission bulk-revoke across one user or many. So there are now two pairs of hands on the kill switch: the user, and the org. (Whichever one notices first.) Why a pipeline owner should care Because users are the trust boundary you keep pretending is somebody else's problem. A leaked PAT in a CI pipeline is rarely a CI bug. It is a human who pasted the token into a script, then a laptop, then a sync folder, then a backup,
AI 资讯
Connect a user's mailbox with Nylas hosted OAuth
Every Nylas request you make on a user's behalf needs one thing first: their permission. Before you can list a mailbox, send on someone's behalf, or read a calendar, the user has to authorize your application through their provider, and that authorization is what's called a grant. Doing the OAuth dance yourself means registering with Google and Microsoft separately, handling each provider's consent screen, token exchange, and refresh quirks. Hosted OAuth collapses that into one flow that works the same across every provider. This post walks through connecting an account from two angles: the HTTP API your web app uses in production, and the nylas CLI for connecting a test account from the terminal. I work on the CLI, so the terminal commands below are the ones I reach for when I need a grant to develop against. What a grant is A grant is an authenticated connection to a single user's account. When a user authorizes your application, Nylas stores the connection and hands you a grant_id , a stable identifier you pass on every subsequent request to act on that user's email, calendar, or contacts. The grant is the unit of access: one user who connected one mailbox is one grant, and everything you build addresses /v3/grants/{grant_id}/... . Keep two credentials distinct here. Your API key authenticates your application to Nylas and goes in the Authorization header on every request; the grant_id identifies which connected user that request acts on. The API key is yours and stays on your backend, while a grant_id is minted per user when they connect. The grant is also where provider differences disappear. A Gmail grant and a Microsoft grant have different OAuth scopes and token mechanics underneath, but once connected, both are just a grant_id you use the same way. That's the point of hosted OAuth: you run one flow, the user picks their provider, and you get back the same kind of identifier regardless of who hosts the mailbox. Hosted OAuth supports Google, Microsoft, Yahoo,
AI 资讯
Importing users without a password reset
Every identity migration guide eventually reaches the same paragraph, and it's always a little apologetic: "users will need to reset their passwords." It gets treated like a law of nature. It isn't. It's a choice, usually forced by a tool that didn't want to do the harder thing. The harder thing is verifying your users' existing password hashes in place, so they sign in after the move with exactly the credentials they had before and never notice anything happened. Whether you can do it comes down to one question: can you get the old hashes, and can the new system verify them? Password hashes are more portable than people think A password hash isn't a secret algorithm. bcrypt is bcrypt. A bcrypt hash carries its own cost factor and salt inside the string, so anything that implements bcrypt can verify a hash any other bcrypt system produced. The same is true of the PBKDF2 format ASP.NET Identity uses: documented, versioned, self-describing. If you know what you're holding, you can check a password against it without ever knowing the password. So a migration that preserves logins doesn't need the plaintext (nobody has it) and doesn't need to re-hash everyone up front. It needs to obtain the stored hashes and verify against them on sign-in, upgrading each one to its own format quietly the first time a user logs in. That last part is lazy migration: carry the old hash, verify it once, replace it transparently. Over a few weeks of normal logins your user table re-hashes itself and the legacy formats age out, with zero resets and zero support tickets. The dual-path bit The wrinkle is that different sources hand you different formats, and a good importer verifies both: From self-hosted Duende / ASP.NET Identity: the V3 PBKDF2 hashes (and any legacy bcrypt) verify natively and rehash on first sign-in. This is the easy case, because it's the same scheme the destination already uses. Most teams are surprised it's that clean. From Auth0: bcrypt hashes verify verbatim. The catch
AI 资讯
Deploying Ory Kratos Open-Source Identity and User Management System on Ubuntu 24.04
Ory Kratos is an open-source, API-first identity and user management system handling registration, login, recovery, verification, and session management with a self-service UI. This guide deploys Kratos using Docker Compose with PostgreSQL, the self-service UI Node, and Traefik handling automatic HTTPS for the public API. By the end, you'll have Kratos managing identities and sessions for users registering through your domain over HTTPS. Prerequisite: SMTP credentials are required for verification and recovery emails. The admin API stays bound to 127.0.0.1 on purpose — never expose it publicly. Set Up the Directory Structure 1. Create the project directories: $ mkdir -p ~/ory-kratos/ { config,data/postgres } $ cd ~/ory-kratos 2. Create the environment file: $ nano .env DOMAIN = kratos.example.com LETSENCRYPT_EMAIL = admin@example.com KRATOS_VERSION = v26.2.0 POSTGRES_USER = kratos POSTGRES_PASSWORD = EXAMPLE_DB_PASSWORD POSTGRES_DB = kratosdb LOG_LEVEL = info 3. Create the identity schema — defines the user fields (email + name) and how the email maps to login, recovery, and verification: $ nano config/identity.schema.json Use the schema described in the Vultr Docs walkthrough — email is the login identifier with password auth; name is a free-text trait. 4. Create the Kratos configuration — public/admin API URLs, password policy (12-char minimum + HaveIBeenPwned), session lifetimes, self-service flows, SMTP courier: $ nano config/kratos.yml Fill in the full configuration from the source article. Key points to keep consistent with the stack below: Public API listens on the internal port and is fronted by Traefik on ${DOMAIN} . Admin API listens on 127.0.0.1:4434 only — used by tooling on the host. The DSN points at the postgres service ( postgres://kratos:...@postgres:5432/kratosdb?sslmode=disable ). The courier section uses your SMTP provider for verification mail. Deploy with Docker Compose 1. Create the Compose manifest: $ nano docker-compose.yml services : traefi
AI 资讯
AWS Adds Multi-Region Replication to Amazon Cognito Identity Service
AWS recently introduced Amazon Cognito multi-region replication, which automatically replicates user identities and user pool configurations from a primary region to a secondary one. This enables applications to continue authenticating users from a replica region during outages, without requiring custom replication and failover mechanisms. By Renato Losio
AI 资讯
AI Agent Identity and Permission Challenges: How Uber and Auth0 Are Rethinking Access Control
Uber recently described an internal architecture for propagating identity across multi-agent AI workflows. The design aims to perserve user context, agent provenance, and scoped access as agents delegate work and call internal tools. The case study aligns with Auth0’s view that AI agents need permissions based on delegated authority, scoped credentials, and explicit human approval boundaries. By Eran Stiller
AI 资讯
Two HNG Tasks That Taught Me More Than the Spec: OAuth for Three Clients, and Shipping AI on a Team Deadline
Two HNG Tasks That Taught Me More Than the Spec This is my Stage 9B write-up for the HNG internship . No new code just two tasks that stuck: one I owned solo across multiple repos, and one I shipped inside a team product under real deadline pressure. If you've ever had auth work almost done for three days straight, or watched an LLM politely ignore your JSON schema, you'll recognize these stories. Task 1 (Individual): Insighta Labs — One API, Three Clients, One Auth System Stage: 3 (Technical Requirements Document / TRD track) Why I picked it: Auth looked "done" on paper. It wasn't. Web portal, CLI, and graders all needed to log in differently, and every environment (localhost, Railway, preview URLs) found a new way to break. What it was Insighta Labs is a queryable profile-intelligence API I built during HNG. By Stage 3 the backend wasn't just CRUD anymore it needed GitHub OAuth with PKCE , JWT access + refresh with rotation , RBAC ( admin vs analyst ), rate limits, API versioning, and three first-class clients : Client Repo How it authenticates Backend API HNG_STAGE-1 Issues tokens, sets cookies Web portal Insighta-WebPortal HTTP-only cookies + CSRF CLI Insighta-Cli PKCE + local callback + Bearer tokens Every /api/* route required X-API-Version: 1 and a valid session. Access tokens expired in 3 minutes ; refresh tokens in 5 minutes with rotation. That sounds harsh, it was intentional, and it surfaced bugs fast. The problem it was solving Reviewers and real users had to prove identity without sharing one login mechanism. Browsers should never see raw tokens in JavaScript. The CLI can't use cookie redirects the same way a React app does. Automated graders needed a test path that didn't depend on GitHub's OAuth exchange. One auth design. Three runtimes. Zero "works on my machine only." How I approached it I split auth into explicit paths instead of one generic "login" handler: Web flow GET /auth/github — server stores PKCE verifier, redirects to GitHub GET /auth/gith
AI 资讯
From OpenSSL to One Click: Meet the Payneteasy Key Pair Factory
Connecting to a payment gateway rarely fails because of business logic. More often, it fails at the very first technical step: authentication. If you’ve ever worked with payment APIs, you know the drill. Before sending a single request, you need to generate a cryptographic key pair and sign every request correctly. Sounds straightforward—until you actually try to do it. The hidden hurdle in every integration To securely call the Payneteasy API, each request must be signed. That means: Generating an RSA key pair (usually via OpenSSL) Converting between PKCS#1 and PKCS#8 formats Building a correct signature base string Percent-encoding everything properly Signing with RSA-SHA256 or HMAC-SHA1 Assembling the Authorization header One small mistake—a missing character, wrong encoding, or incorrect format—and your request gets rejected. For teams without deep cryptography expertise, this step alone can turn a one-day integration into a week-long debugging session. If you’re curious, the full manual process is documented here: https://doc.payneteasy.com/integration/general_api_usage/request_authentication_methods/oauth.html#generating-key-pair The solution: Key Pair Factory We built the Payneteasy Key Pair Factory to remove this bottleneck entirely. Instead of dealing with OpenSSL commands and key formats, you can generate everything you need in just a few clicks. What it does: Generates a ready-to-use RSA key pair Ensures correct formatting for Payneteasy APIs Eliminates manual conversion and configuration errors Keeps the private key on your side Provides a public key for request verification No cryptography expertise required. The tool is open-source and available on GitHub: https://github.com/payneteasy/key-pair-factory Why this matters This is not just about convenience—it directly impacts integration speed and success. With the Key Pair Factory, you get: Faster onboarding Fewer integration errors Less back-and-forth with support teams A smoother developer experience I
AI 资讯
OAuth for Remote MCP Servers
OAuth for Remote MCP Servers How each AI assistant signs in to a remote MCP (Model Context Protocol) server, and why the flow differs by client and by where it runs. Overview The protocol throughout is standard OAuth 2.1 — an open, widely implemented authorization standard. The human sign-in runs through oauth2-proxy , one of the most widely deployed open-source auth proxies; the only deployment-specific piece is a thin, spec-conforming authorization server (the /oauth endpoints) that hands MCP clients their tokens. Every client ends up the same way — a person signs in against Google (restricted to your organization's domain), and the client holds a short-lived bearer token it presents on each /mcp call. Two things differ between assistants: where the client runs (a machine on the VPN — private — vs. the vendor's cloud — public ), which decides the host it reaches; and what kind of OAuth client it is — a public client proving itself with PKCE (Proof Key for Code Exchange, which lets a client with no secret prove the token request comes from the same client that started the flow), or a confidential client proving itself with a secret. The participants oauth2-proxy — the public-facing reverse proxy. It authenticates the human against Google (the sign-in restricted to your organization's domain) and forwards the verified identity to the app behind it. Only oauth2-proxy faces the internet. It is a mature, heavily-deployed open-source project — the standard way to put Google/OIDC (OpenID Connect) single sign-on in front of a service, widely used in Kubernetes deployments — so the most security-sensitive leg of the flow (the OAuth exchange with the identity provider) runs on battle-tested code. The MCP server — the app on a loopback port behind the proxy. It plays two roles: the OAuth authorization server ( /oauth/authorize , /oauth/token , /oauth/register , .well-known discovery) and the /mcp tool endpoint. It mints codes and tokens, and validates a token on every /mcp c
AI 资讯
How we made our niche-industry SaaS MCP-ready (and watched ChatGPT call our dispatch tools)
Note: This is an English digest of the original Zenn post (Japanese) . Read there for the full timeline and commit-level trace. TL;DR We ship tasteck , a B2B SaaS for the Japanese night-leisure industry (dispatch + cast shift management). 8 years of operational data, ~100 venues live. Two days after the MCP design post , ChatGPT Plus can call our tools live: "Who's available tonight?" → MCP list_available_drivers → JSON → natural-language reply. Estimated B2 OAuth sprint = 2 weeks (6/16–7/1). Actual = 1 day , by reading the spec carefully before touching code. We hit 12 distinct traps between "OAuth issuance works" and "ChatGPT actually invokes the tool." The QA logs caught every one. What we shipped 3 read tools (B1): list_available_drivers — drivers free tonight list_cast_shifts — today's cast shift roster list_assignable_casts — joined resolution: roster ∧ stage-name set ∧ shop match Natural-language date helper: resolveBusinessDate(naturalText, company) — handles "today / tomorrow / day-after-tomorrow" and the per-tenant business-day boundary (e.g. day flips at 04:00 or 05:00, configured per Company.changeDateTime ). MCP SDK Server + SSE transport: @modelcontextprotocol/sdk wired into a NestJS controller. One SSE connection = one McpServer instance, company-scoped, with a session_id Map routing POST /messages . OAuth flow (B2, finished in one day across 7 steps) Step What Commit 1 Protected Resource Metadata endpoint (RFC 9728) d6f05ff6 2 /authorize + consent screen + PKCE start 107edbcb 3 /token + PKCE verify + JWT issue + resource (RFC 8707) ffd0468c 4 OAuthAccessTokenGuard (RS256 + HS256 fallback, extracts companyId / staffId ) f2c9bed4 5 Streamable HTTP transport (SSE → POST /sse/:companyId for JSON-RPC) 3a28d92f 6 resolveBusinessDate undefined fallback (`(naturalText 7 QA redeploy + ChatGPT live demo — The 12 traps (compressed) The full timeline is in the Japanese post; the abridged list: Discovery path mismatch. ChatGPT expected {% raw %} .well-known/oauth
AI 资讯
known_hosts
1. Introduction As the golden standard of secure remote access , the Secure Shell (SSH) protocol has several layers of protection. One of them involves recording and keeping track of the known servers on the client side. known_hosts By default, the known_hosts file for a given user is located at: cat /home/user_name/.ssh/known_hosts github.com ssh-rsa *** github.com ecdsa-sha2-nistp256 *** github.com ssh-ed25519 *** Basically, the file contains a list with several columns, separated by whitespace: Identifying host data Host key type Host key value Optional comment The first column can be hashed or cleartext, depending on the setting of HashKnownHosts in /etc/ssh/ssh_config . When hashed, the first field of each line starts with |1| , a HASH_MAGIC marker. After the latter, the field continues with a random 160-bit string, otherwise known as a salt, followed by a 160-bit SHA1 hash. Each of these is encoded in base64 . The main idea is to hide the IP address or hostname data, which would otherwise be directly visible Either way, known_hosts contains a mapping between a server as identified by its characteristics and its key . ## Known Hosts Checking When connecting to a remote host, SSH checks the known_hosts file of the client to confirm the address or hostname for the server match the key we get from it . If there is a match, the session setup can continue. Otherwise, we get an error. The entry for 192.168.6.66 in the known_hosts file doesn’t match the (Elliptic Curve Digital Signature Algorithm, ECDSA ) key we got back from the server at that address . Critically, if we don’t know what caused the error, we should heed the text in capital letters: something nasty can indeed be happening . On the other hand, the reasons for such an issue can be valid and trivial: dynamic IP address changed hostname reinstalled system reinstalled SSH Docker container misconfigured DHCP relocated client In fact, there can be many more. ## Bypass Known Hosts The error text when connectin