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