<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: oauth</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/oauth.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2025-11-08T22:04:45+00:00</updated><author><name>Simon Willison</name></author><entry><title>Quoting Kenton Varda</title><link href="https://simonwillison.net/2025/Nov/8/kenton-varda/#atom-tag" rel="alternate"/><published>2025-11-08T22:04:45+00:00</published><updated>2025-11-08T22:04:45+00:00</updated><id>https://simonwillison.net/2025/Nov/8/kenton-varda/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://x.com/kentonvarda/status/1987208904724652273"&gt;&lt;p&gt;The big advantage of MCP over OpenAPI is that it is very clear about auth. [...]&lt;/p&gt;
&lt;p&gt;Maybe an agent could read the docs and write code to auth. But we don't actually want that, because it implies the agent gets access to the API token! We want the agent's harness to handle that and never reveal the key to the agent. [...]&lt;/p&gt;
&lt;p&gt;OAuth has always assumed that the client knows what API it's talking to, and so the client's developer can register the client with that API in advance to get a client_id/client_secret pair. Agents, though, don't know what MCPs they'll talk to in advance.&lt;/p&gt;
&lt;p&gt;So MCP &lt;a href="https://modelcontextprotocol.io/specification/draft/basic/authorization#dynamic-client-registration"&gt;requires OAuth dynamic client registration&lt;/a&gt; (&lt;a href="https://datatracker.ietf.org/doc/html/rfc7591"&gt;RFC 7591&lt;/a&gt;), which practically nobody actually implemented prior to MCP. DCR might as well have been introduced by MCP, and may actually be the most important unlock in the whole spec.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://x.com/kentonvarda/status/1987208904724652273"&gt;Kenton Varda&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/kenton-varda"&gt;kenton-varda&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/model-context-protocol"&gt;model-context-protocol&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;&lt;/p&gt;



</summary><category term="kenton-varda"/><category term="security"/><category term="oauth"/><category term="model-context-protocol"/><category term="generative-ai"/><category term="ai"/><category term="llms"/></entry><entry><title>Claude 3.7 Sonnet and Claude Code</title><link href="https://simonwillison.net/2025/Feb/24/claude-37-sonnet-and-claude-code/#atom-tag" rel="alternate"/><published>2025-02-24T20:25:39+00:00</published><updated>2025-02-24T20:25:39+00:00</updated><id>https://simonwillison.net/2025/Feb/24/claude-37-sonnet-and-claude-code/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.anthropic.com/news/claude-3-7-sonnet"&gt;Claude 3.7 Sonnet and Claude Code&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Anthropic released &lt;strong&gt;Claude 3.7 Sonnet&lt;/strong&gt; today - skipping the name "Claude 3.6" because the Anthropic user community had already started using that as the unofficial name for their &lt;a href="https://www.anthropic.com/news/3-5-models-and-computer-use"&gt;October update to 3.5 Sonnet&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As you may expect, 3.7 Sonnet is an improvement over 3.5 Sonnet - and is priced the same, at $3/million tokens for input and $15/m output.&lt;/p&gt;
&lt;p&gt;The big difference is that this is Anthropic's first "reasoning" model - applying the same trick that we've now seen from OpenAI o1 and o3, Grok 3, Google Gemini 2.0 Thinking, DeepSeek R1 and Qwen's QwQ and QvQ. The only big model families without an official reasoning model now are Mistral and Meta's Llama.&lt;/p&gt;
&lt;p&gt;I'm still working on &lt;a href="https://github.com/simonw/llm-anthropic/pull/15"&gt;adding support to my llm-anthropic plugin&lt;/a&gt; but I've got enough working code that I was able to get it to draw me a pelican riding a bicycle. Here's the non-reasoning model:&lt;/p&gt;
&lt;p style="text-align: center"&gt;&lt;img src="https://static.simonwillison.net/static/2025/pelican-claude-3.7-sonnet.svg" alt="A very good attempt"&gt;&lt;/p&gt;

&lt;p&gt;And here's that same prompt but with "thinking mode" enabled:&lt;/p&gt;
&lt;p style="text-align: center"&gt;&lt;img src="https://static.simonwillison.net/static/2025/pelican-claude-3.7-sonnet-thinking.svg" alt="A very good attempt"&gt;&lt;/p&gt;

&lt;p&gt;Here's &lt;a href="https://gist.github.com/simonw/9c2d119f815b4a6c3802ab591857bf40"&gt;the transcript&lt;/a&gt; for that second one, which mixes together the thinking and the output tokens. I'm still working through how best to differentiate between those two types of token.&lt;/p&gt;
&lt;p&gt;Claude 3.7 Sonnet has a training cut-off date of Oct 2024 - an improvement on 3.5 Haiku's July 2024 - and can output up to 64,000 tokens in thinking mode (some of which are used for thinking tokens) and up to 128,000 if you enable &lt;a href="https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking#extended-output-capabilities-beta"&gt;a special header&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Claude 3.7 Sonnet can produce substantially longer responses than previous models with support for up to 128K output tokens (beta)---more than 15x longer than other Claude models. This expanded capability is particularly effective for extended thinking use cases involving complex reasoning, rich code generation, and comprehensive content creation.&lt;/p&gt;
&lt;p&gt;This feature can be enabled by passing an &lt;code&gt;anthropic-beta&lt;/code&gt; header of &lt;code&gt;output-128k-2025-02-19&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Anthropic's other big release today is a preview of &lt;strong&gt;Claude Code&lt;/strong&gt; - a CLI tool for interacting with Claude that includes the ability to prompt Claude in terminal chat and have it read and modify files and execute commands. This means it can both iterate on code and execute tests, making it an extremely powerful "agent" for coding assistance.&lt;/p&gt;
&lt;p&gt;Here's &lt;a href="https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview"&gt;Anthropic's documentation&lt;/a&gt; on getting started with Claude Code, which uses OAuth (a first for Anthropic's API) to authenticate against your API account, so you'll need to configure billing.&lt;/p&gt;
&lt;p&gt;Short version:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install -g @anthropic-ai/claude-code
claude
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It can burn a lot of tokens so don't be surprised if a lengthy session with it adds up to single digit dollars of API spend.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/cli"&gt;cli&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-assisted-programming"&gt;ai-assisted-programming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm"&gt;llm&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/anthropic"&gt;anthropic&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude"&gt;claude&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-agents"&gt;ai-agents&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pelican-riding-a-bicycle"&gt;pelican-riding-a-bicycle&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm-reasoning"&gt;llm-reasoning&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm-release"&gt;llm-release&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/coding-agents"&gt;coding-agents&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude-code"&gt;claude-code&lt;/a&gt;&lt;/p&gt;



</summary><category term="cli"/><category term="oauth"/><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="ai-assisted-programming"/><category term="llm"/><category term="anthropic"/><category term="claude"/><category term="ai-agents"/><category term="pelican-riding-a-bicycle"/><category term="llm-reasoning"/><category term="llm-release"/><category term="coding-agents"/><category term="claude-code"/></entry><entry><title>GitHub OAuth for a static site using Cloudflare Workers</title><link href="https://simonwillison.net/2024/Nov/29/github-oauth-cloudflare/#atom-tag" rel="alternate"/><published>2024-11-29T18:13:18+00:00</published><updated>2024-11-29T18:13:18+00:00</updated><id>https://simonwillison.net/2024/Nov/29/github-oauth-cloudflare/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://til.simonwillison.net/cloudflare/workers-github-oauth"&gt;GitHub OAuth for a static site using Cloudflare Workers&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Here's a TIL covering a Thanksgiving AI-assisted programming project. I wanted to add OAuth against GitHub to some of the projects on my &lt;a href="https://tools.simonwillison.net/"&gt;tools.simonwillison.net&lt;/a&gt; site in order to implement "Save to Gist".&lt;/p&gt;
&lt;p&gt;That site is entirely statically hosted by GitHub Pages, but OAuth has a required server-side component: there's a &lt;code&gt;client_secret&lt;/code&gt; involved that should never be included in client-side code.&lt;/p&gt;
&lt;p&gt;Since I serve the site from behind Cloudflare I realized that a minimal &lt;a href="https://workers.cloudflare.com/"&gt;Cloudflare Workers&lt;/a&gt; script may be enough to plug the gap. I got Claude on my phone to build me a prototype and then pasted that (still on my phone) into a new Cloudflare Worker and it worked!&lt;/p&gt;
&lt;p&gt;... almost. On later closer inspection of the code it was missing error handling... and then someone pointed out it was vulnerable to a login CSRF attack thanks to failure to check the &lt;code&gt;state=&lt;/code&gt; parameter. I worked with Claude to fix those too.&lt;/p&gt;
&lt;p&gt;Useful reminder here that pasting code AI-generated code around on a mobile phone isn't necessarily the best environment to encourage a thorough code review!


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/csrf"&gt;csrf&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/github"&gt;github&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/projects"&gt;projects&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/tools"&gt;tools&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/cloudflare"&gt;cloudflare&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-assisted-programming"&gt;ai-assisted-programming&lt;/a&gt;&lt;/p&gt;



</summary><category term="csrf"/><category term="github"/><category term="oauth"/><category term="projects"/><category term="security"/><category term="tools"/><category term="ai"/><category term="cloudflare"/><category term="generative-ai"/><category term="llms"/><category term="ai-assisted-programming"/></entry><entry><title>Grant Negotiation and Authorization Protocol (GNAP)</title><link href="https://simonwillison.net/2024/Oct/14/grant-negotiation-and-authorization-protocol-gnap/#atom-tag" rel="alternate"/><published>2024-10-14T05:22:15+00:00</published><updated>2024-10-14T05:22:15+00:00</updated><id>https://simonwillison.net/2024/Oct/14/grant-negotiation-and-authorization-protocol-gnap/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc9635"&gt;Grant Negotiation and Authorization Protocol (GNAP)&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
RFC 9635 was published a few days ago. GNAP is effectively OAuth 3 - it's a newly standardized design for a protocol for delegating authorization so an application can access data on your behalf.&lt;/p&gt;
&lt;p&gt;The most interesting difference between GNAP and OAuth 2 is that GNAP no longer requires clients to be registered in advance. With OAuth the &lt;code&gt;client_id&lt;/code&gt; and &lt;code&gt;client_secret&lt;/code&gt; need to be configured for each application, which means applications need to register with their targets - creating a new application on GitHub or Twitter before implementing the authorization flow, for example.&lt;/p&gt;
&lt;p&gt;With GNAP that's no longer necessary. The protocol allows a client to provide a key as part of the first request to the server which is then used in later stages of the interaction.&lt;/p&gt;
&lt;p&gt;GNAP has been brewing for a &lt;em&gt;long&lt;/em&gt; time. The IETF working group &lt;a href="https://datatracker.ietf.org/doc/charter-ietf-gnap/"&gt;was chartered in 2020&lt;/a&gt;, and two of the example implementations (&lt;a href="https://github.com/interop-alliance/gnap-client-js"&gt;gnap-client-js&lt;/a&gt; and &lt;a href="https://github.com/securekey/oauth-xyz-nodejs"&gt;oauth-xyz-nodejs&lt;/a&gt;) last saw commits more than four years ago.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://lobste.rs/s/e1gujd/rfc_9635_grant_negotiation"&gt;lobste.rs&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rfc"&gt;rfc&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;&lt;/p&gt;



</summary><category term="oauth"/><category term="rfc"/><category term="security"/></entry><entry><title>OAuth from First Principles</title><link href="https://simonwillison.net/2024/Sep/5/oauth-from-first-principles/#atom-tag" rel="alternate"/><published>2024-09-05T22:43:40+00:00</published><updated>2024-09-05T22:43:40+00:00</updated><id>https://simonwillison.net/2024/Sep/5/oauth-from-first-principles/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://stack-auth.com/blog/oauth-from-first-principles"&gt;OAuth from First Principles&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Rare example of an OAuth explainer that breaks down &lt;em&gt;why&lt;/em&gt; each of the steps are designed the way they are, by showing an illustrative example of how an attack against OAuth could work in absence of each measure.&lt;/p&gt;
&lt;p&gt;Ever wondered why OAuth returns you an authorization code which you then need to exchange for an access token, rather than returning the access token directly? It's for an added layer of protection against eavesdropping attacks:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If Endframe eavesdrops the authorization code in real-time, they can exchange it for an access token very quickly, before Big Head's browser does. [...] Currently, anyone with the authorization code can exchange it for an access token. We need to ensure that only the person who initiated the request can do the exchange.&lt;/p&gt;
&lt;/blockquote&gt;

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=41420783"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;&lt;/p&gt;



</summary><category term="oauth"/><category term="security"/></entry><entry><title>Musing about OAuth and LLMs on Mastodon</title><link href="https://simonwillison.net/2024/Aug/24/oauth-llms/#atom-tag" rel="alternate"/><published>2024-08-24T00:29:47+00:00</published><updated>2024-08-24T00:29:47+00:00</updated><id>https://simonwillison.net/2024/Aug/24/oauth-llms/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://fedi.simonwillison.net/@simon/113014147494012212"&gt;Musing about OAuth and LLMs on Mastodon&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Lots of people are asking why Anthropic and OpenAI don't support OAuth, so you can bounce users through those providers to get a token that uses their API budget for your app.&lt;/p&gt;
&lt;p&gt;My guess: they're worried malicious app developers would use it to trick people and obtain valid API keys.&lt;/p&gt;
&lt;p&gt;Imagine a version of my dumb little &lt;a href="https://tools.simonwillison.net/haiku"&gt;write a haiku about a photo you take&lt;/a&gt; page which used OAuth, harvested API keys and then racked up hundreds of dollar bills against everyone who tried it out running illicit election interference campaigns or whatever.&lt;/p&gt;
&lt;p&gt;I'm trying to think of an OAuth API that dishes out tokens which effectively let you &lt;em&gt;spend money on behalf of your users&lt;/em&gt; and I can't think of any - OAuth is great for "grant this app access to data that I want to share", but "spend money on my behalf" is a whole other ball game.&lt;/p&gt;
&lt;p&gt;I guess there's a version of this that could work: it's OAuth but users get to set a spending limit of e.g. $1 (maybe with the authenticating app suggesting what that limit should be).&lt;/p&gt;
&lt;p&gt;Here's a counter-example &lt;a href="https://twitter.com/hammer_mt/status/1827144780650017162"&gt;from Mike Taylor&lt;/a&gt; of a category of applications that do use OAuth to authorize spend on behalf of users:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I used to work in advertising and plenty of applications use OAuth to connect your Facebook and Google ads accounts, and they could do things like spend all your budget on disinformation ads, but in practice I haven't heard of a single case. When you create a dev application there are stages of approval so you can only invite a handful of beta users directly until the organization and app gets approved.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In which case maybe the cost for providers here is in review and moderation: if you’re going to run an OAuth API that lets apps spend money on behalf of their users you need to actively monitor your developer community and review and approve their apps.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openai"&gt;openai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/anthropic"&gt;anthropic&lt;/a&gt;&lt;/p&gt;



</summary><category term="oauth"/><category term="openai"/><category term="llms"/><category term="anthropic"/></entry><entry><title>Oh-Auth - Abusing OAuth to take over millions of accounts</title><link href="https://simonwillison.net/2023/Oct/26/oauth/#atom-tag" rel="alternate"/><published>2023-10-26T15:51:20+00:00</published><updated>2023-10-26T15:51:20+00:00</updated><id>https://simonwillison.net/2023/Oct/26/oauth/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://salt.security/blog/oh-auth-abusing-oauth-to-take-over-millions-of-accounts"&gt;Oh-Auth - Abusing OAuth to take over millions of accounts&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Describes an attack against vulnerable implementations of OAuth.&lt;/p&gt;

&lt;p&gt;Let’s say your application uses OAuth against Facebook, and then takes the returned Facebook token and gives it access to the user account with the matching email address passed in the token from Facebook.&lt;/p&gt;

&lt;p&gt;It’s critical that you also confirm the token was generated for your own application, not something else. Otherwise any secretly malicious app online that uses Facebook login could take on of their stored tokens and use it to hijack an account of your site belonging to that user’s email address.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=38009291"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;&lt;/p&gt;



</summary><category term="oauth"/><category term="security"/></entry><entry><title>Weeknotes: datasette-auth0</title><link href="https://simonwillison.net/2022/Mar/28/datasette-auth0/#atom-tag" rel="alternate"/><published>2022-03-28T04:40:42+00:00</published><updated>2022-03-28T04:40:42+00:00</updated><id>https://simonwillison.net/2022/Mar/28/datasette-auth0/#atom-tag</id><summary type="html">
    &lt;p&gt;Datasette 0.61, a Twitter Space and a new Datasette plugin for authenticating against Auth0.&lt;/p&gt;
&lt;h4&gt;datasette-auth0&lt;/h4&gt;
&lt;p&gt;I've been figuring out how best to integrate with &lt;a href="https://auth0.com/"&gt;Auth0&lt;/a&gt; for account management and sign-in, for a project I'm working on with &lt;a href="https://blog.natbat.net/"&gt;Natalie&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I used Auth0 for &lt;a href="https://github.com/CAVaccineInventory/vial"&gt;VIAL&lt;/a&gt; with Vaccinate CA last year, following the &lt;a href="https://auth0.com/docs/quickstart/webapp/django/01-login"&gt;Auth0 Django tutorial&lt;/a&gt; using &lt;a href="https://python-social-auth.readthedocs.io/en/latest/"&gt;Python Social Auth&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This time I decided to try and do it from first principles rather than use a library, for reasons I discussed in &lt;a href="https://twitter.com/simonw/status/1507847567454851076"&gt;this Twitter thread&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It turns out Auth0 is using regular OAuth 2, which can be implemented from scratch in just three steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Generate a URL to a page on Auth0 that will display the login screen&lt;/li&gt;
&lt;li&gt;Implement a page that handles the redirect back from Auth0, which needs to exchange the code from the &lt;code&gt;?code=&lt;/code&gt; parameter for an access token by POSTing it to an authenticated API endpoint&lt;/li&gt;
&lt;li&gt;Use that access token to retrieve the authenticated user's profile&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I wrote up the steps in this TIL: &lt;a href="https://til.simonwillison.net/auth0/oauth-with-auth0"&gt;Simplest possible OAuth authentication with Auth0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Since it turned out to be pretty straight-forward, I turned it into a new authentication plugin for Datasette: &lt;a href="https://datasette.io/plugins/datasette-auth0"&gt;datasette-auth0&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can try that out with the live demo at &lt;a href="https://datasette-auth0-demo.datasette.io/"&gt;datasette-auth0-demo.datasette.io&lt;/a&gt; - click on the top right menu icon and select "Sign in with Auth0".&lt;/p&gt;
&lt;p&gt;&lt;img src="https://static.simonwillison.net/static/2022/datasette-auth0.gif" alt="Animated demo of the datasette-auth0 sign-in flow" style="max-width:100%;" /&gt;&lt;/p&gt;
&lt;p&gt;The live demo is deployed automatically any time a push to the &lt;code&gt;main&lt;/code&gt; branch passes its tests. I've implemented this pattern a few times now, so I wrote it up in another TIL: &lt;a href="https://til.simonwillison.net/github-actions/deploy-live-demo-when-tests-pass"&gt;Deploying a live Datasette demo when the tests pass&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Datasette 0.61.0 (and 0.61.1)&lt;/h4&gt;
&lt;p&gt;I wrote about these in &lt;a href="https://simonwillison.net/2022/Mar/24/datasette-061/"&gt;the annotated weeknotes&lt;/a&gt;. They were pretty significant releases, representing &lt;a href="https://github.com/simonw/datasette/compare/0.60.2...0.61.1"&gt;86 commits&lt;/a&gt; since 0.60.2 released back in January.&lt;/p&gt;
&lt;h4 id="new-features-as-documentation"&gt;New features as documentation&lt;/h4&gt;
&lt;p&gt;Some of my favourite feature requests for my projects are ones that can be solved by documentation. I had a great example of that this week.&lt;/p&gt;
&lt;p&gt;In &lt;a href="https://github.com/simonw/sqlite-utils/issues/420"&gt;#420: Transform command with shared context&lt;/a&gt; Mehmet Sukan wanted a way to speed up the following operation using &lt;code&gt;sqlite-utils insert --convert&lt;/code&gt; - described in &lt;a href="https://simonwillison.net/2022/Jan/11/sqlite-utils/"&gt;What’s new in sqlite-utils 3.20 and 3.21&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell"&gt;&lt;pre&gt;cat items.json &lt;span class="pl-k"&gt;|&lt;/span&gt; jq &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;.data&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-k"&gt;|&lt;/span&gt; sqlite-utils insert listings.db listings - --convert &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-s"&gt;d = enchant.Dict("en_US")&lt;/span&gt;
&lt;span class="pl-s"&gt;row["is_dictionary_word"] = d.check(row["name"])&lt;/span&gt;
&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; --import=enchant --ignore&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;--convert&lt;/code&gt; option lets you specify Python code that will be executed against each inserted item. Mehmet's problem was that the &lt;code&gt;enchant.Dict("en_US")&lt;/code&gt; operation is quite expensive, and it was being run every time around the loop.&lt;/p&gt;
&lt;p&gt;I started looking into ways to speed this up... and realized that there was already a mechanism for doing this, but it was undocumented and I hadn't previously realized it was even possible!&lt;/p&gt;
&lt;p&gt;The recipe that works looks like this:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell"&gt;&lt;pre&gt;&lt;span class="pl-c1"&gt;echo&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;[&lt;/span&gt;
&lt;span class="pl-s"&gt;  {"name": "notaword"},&lt;/span&gt;
&lt;span class="pl-s"&gt;  {"name": "word"}&lt;/span&gt;
&lt;span class="pl-s"&gt;]&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-k"&gt;|&lt;/span&gt; python3 -m sqlite_utils insert listings.db listings - --convert &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-s"&gt;import enchant&lt;/span&gt;
&lt;span class="pl-s"&gt;d = enchant.Dict("en_US")&lt;/span&gt;
&lt;span class="pl-s"&gt;&lt;/span&gt;
&lt;span class="pl-s"&gt;def convert(row):&lt;/span&gt;
&lt;span class="pl-s"&gt;    global d&lt;/span&gt;
&lt;span class="pl-s"&gt;    row["is_dictionary_word"] = d.check(row["name"])&lt;/span&gt;
&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The result:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell"&gt;&lt;pre&gt;% sqlite-utils rows listings.db listings        
[{&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;name&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;notaword&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;is_dictionary_word&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: 0},
 {&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;name&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;word&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;is_dictionary_word&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;: 1}]&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This takes advantage of a feature of the &lt;code&gt;sqlite-utils&lt;/code&gt; Python snippet mechanism, which &lt;a href="https://github.com/simonw/sqlite-utils/blob/95522ad919f96eb6cc8cd3cd30389b534680c717/sqlite_utils/utils.py#L308-L342"&gt;is implemented here&lt;/a&gt;. It first attempts &lt;code&gt;exec()&lt;/code&gt; against the provided code to see if it defined a &lt;code&gt;convert(value)&lt;/code&gt; function - if that fails, it composes a function body (to cover simple expressions like &lt;code&gt;row["ok"] = True&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;So I got to close the issue by &lt;a href="https://sqlite-utils.datasette.io/en/latest/cli.html#using-a-convert-function-to-execute-initialization"&gt;adding some documentation&lt;/a&gt; showing how to do this!&lt;/p&gt;
&lt;p&gt;Another, smaller example this week: when I figured out &lt;a href="https://til.simonwillison.net/shot-scraper/readability"&gt;Extracting web page content using Readability.js and shot-scraper&lt;/a&gt; I learned that Playwright can accept and execute &lt;code&gt;async () =&amp;gt; {...}&lt;/code&gt; functions, enabling this pattern:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell"&gt;&lt;pre&gt;shot-scraper javascript https://simonwillison.net/2022/Mar/24/datasette-061/ &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-s"&gt;async () =&amp;gt; {&lt;/span&gt;
&lt;span class="pl-s"&gt;  const readability = await import('https://cdn.skypack.dev/@mozilla/readability');&lt;/span&gt;
&lt;span class="pl-s"&gt;  return (new readability.Readability(document)).parse();&lt;/span&gt;
&lt;span class="pl-s"&gt;}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So I &lt;a href="https://github.com/simonw/shot-scraper/commit/8d103ae6121031ea7a8799fcac4d2d2dcf8525a2"&gt;added that pattern&lt;/a&gt; to the &lt;code&gt;shot-scraper&lt;/code&gt; documentation.&lt;/p&gt;
&lt;h4&gt;SQLite Happy Hour Twitter Space&lt;/h4&gt;
&lt;p&gt;I hosted my first Twitter Space. The recording and notes can be found in &lt;a href="https://simonwillison.net/2022/Mar/23/sqlite-happy-hour/"&gt;SQLite Happy Hour—a Twitter Spaces conversation about three interesting projects building on SQLite&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also learned how to download the audio of a Twitter Spaces in two different ways, as documented in my TIL on &lt;a href="https://til.simonwillison.net/twitter/export-edit-twitter-spaces"&gt;Exporting and editing a Twitter Spaces recording&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Releases this week&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/simonw/datasette-auth0"&gt;datasette-auth0&lt;/a&gt;&lt;/strong&gt;: &lt;a href="https://github.com/simonw/datasette-auth0/releases/tag/0.1a0"&gt;0.1&lt;/a&gt; - 2022-03-27
&lt;br /&gt;Datasette plugin that authenticates users using Auth0&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/simonw/datasette-packages"&gt;datasette-packages&lt;/a&gt;&lt;/strong&gt;: &lt;a href="https://github.com/simonw/datasette-packages/releases/tag/0.1.1"&gt;0.1.1&lt;/a&gt; - (&lt;a href="https://github.com/simonw/datasette-packages/releases"&gt;2 releases total&lt;/a&gt;) - 2022-03-25
&lt;br /&gt;Show a list of currently installed Python packages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/simonw/datasette-hashed-urls"&gt;datasette-hashed-urls&lt;/a&gt;&lt;/strong&gt;: &lt;a href="https://github.com/simonw/datasette-hashed-urls/releases/tag/0.4"&gt;0.4&lt;/a&gt; - (&lt;a href="https://github.com/simonw/datasette-hashed-urls/releases"&gt;5 releases total&lt;/a&gt;) - 2022-03-24
&lt;br /&gt;Optimize Datasette performance behind a caching proxy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/simonw/datasette"&gt;datasette&lt;/a&gt;&lt;/strong&gt;: &lt;a href="https://github.com/simonw/datasette/releases/tag/0.61.1"&gt;0.61.1&lt;/a&gt; - (&lt;a href="https://github.com/simonw/datasette/releases"&gt;110 releases total&lt;/a&gt;) - 2022-03-23
&lt;br /&gt;An open source multi-tool for exploring and publishing data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/simonw/datasette-publish-vercel"&gt;datasette-publish-vercel&lt;/a&gt;&lt;/strong&gt;: &lt;a href="https://github.com/simonw/datasette-publish-vercel/releases/tag/0.13"&gt;0.13&lt;/a&gt; - (&lt;a href="https://github.com/simonw/datasette-publish-vercel/releases"&gt;20 releases total&lt;/a&gt;) - 2022-03-20
&lt;br /&gt;Datasette plugin for publishing data using Vercel&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;TIL this Weeknotes&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://til.simonwillison.net/pytest/async-fixtures"&gt;Async fixtures with pytest-asyncio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://til.simonwillison.net/sqlite/simple-recursive-cte"&gt;The simplest recursive CTE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://til.simonwillison.net/sqlite/counting-vm-ops"&gt;Counting SQLite virtual machine operations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://til.simonwillison.net/github-actions/npm-cache-with-npx-no-package"&gt;Using the GitHub Actions cache with npx and no package.json&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://til.simonwillison.net/git/rewrite-repo-specific-files"&gt;Rewriting a repo to contain the history of just specific files&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://til.simonwillison.net/twitter/export-edit-twitter-spaces"&gt;Exporting and editing a Twitter Spaces recording&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://til.simonwillison.net/shot-scraper/readability"&gt;Extracting web page content using Readability.js and shot-scraper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://til.simonwillison.net/auth0/oauth-with-auth0"&gt;Simplest possible OAuth authentication with Auth0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://til.simonwillison.net/github-actions/deploy-live-demo-when-tests-pass"&gt;Deploying a live Datasette demo when the tests pass&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/weeknotes"&gt;weeknotes&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite-utils"&gt;sqlite-utils&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="oauth"/><category term="datasette"/><category term="weeknotes"/><category term="sqlite-utils"/></entry><entry><title>Get your own Pocket OAuth token</title><link href="https://simonwillison.net/2019/Oct/5/get-your-own-pocket-oauth-token/#atom-tag" rel="alternate"/><published>2019-10-05T21:56:38+00:00</published><updated>2019-10-05T21:56:38+00:00</updated><id>https://simonwillison.net/2019/Oct/5/get-your-own-pocket-oauth-token/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://your-pocket-oauth-token.glitch.me/"&gt;Get your own Pocket OAuth token&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
I hate it when APIs make you jump through extensive hoops just to get an access token for pulling data directly from your own personal account. I’ve been playing with the Pocket API today and it has a pretty complex OAuth flow, so I built a tiny Flask app on Glitch which helps go through the steps to get an API token for your own personal Pocket account.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://gist.github.com/simonw/cfbec5ee35738ee2d5f6459eb92b1925"&gt;Source code for your-pocket-oauth-token.glitch.me&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/glitch"&gt;glitch&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/mozilla"&gt;mozilla&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;&lt;/p&gt;



</summary><category term="glitch"/><category term="mozilla"/><category term="oauth"/></entry><entry><title>datasette-auth-github</title><link href="https://simonwillison.net/2019/Jul/8/datasette-auth-github/#atom-tag" rel="alternate"/><published>2019-07-08T04:28:17+00:00</published><updated>2019-07-08T04:28:17+00:00</updated><id>https://simonwillison.net/2019/Jul/8/datasette-auth-github/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/simonw/datasette-auth-github"&gt;datasette-auth-github&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
My first big ASGI plugin for Datasette: datasette-auth-github adds the ability to require users to authenticate against the GitHub OAuth API. You can whitelist specific users, or you can restrict access to members of specific GitHub organizations or teams. While it’s structured as a Datasette plugin it also includes ASGI middleware which can be applied to any ASGI application.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/simonw/status/1148085030448578561"&gt;@simonw&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/github"&gt;github&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/projects"&gt;projects&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/asgi"&gt;asgi&lt;/a&gt;&lt;/p&gt;



</summary><category term="github"/><category term="oauth"/><category term="projects"/><category term="datasette"/><category term="asgi"/></entry><entry><title>python-twitter/get_access_token.py</title><link href="https://simonwillison.net/2018/Oct/28/twitter-access-token/#atom-tag" rel="alternate"/><published>2018-10-28T17:25:46+00:00</published><updated>2018-10-28T17:25:46+00:00</updated><id>https://simonwillison.net/2018/Oct/28/twitter-access-token/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/bear/python-twitter/blob/be6f2b3a979429176eeb11c01f211ba8fddc8a92/get_access_token.py"&gt;python-twitter/get_access_token.py&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Creating an OAuth token for accessing a specific Twitter account is way harder than it needs to be. I was about to write my own command-line script for doing this using PIN-based authentication (where you pop open a browser showing the Twitter login flow, then get a PIN number at the end which you paste back into your script) when I discovered that the python-twitter library already ships with a script to do exactly that. Just run “python get_access_token.py”, paste in your app’s consumer key and secret, follow a link, enter the resulting PIN and the script will spit out the consumer_key / consumer_secret / access_token_key / access_token_secret combo you need to start using the Twitter API.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/twitter"&gt;twitter&lt;/a&gt;&lt;/p&gt;



</summary><category term="oauth"/><category term="twitter"/></entry><entry><title>What are some scalable OAuth and OpenID server implementations?</title><link href="https://simonwillison.net/2010/Dec/5/what-are-some-scalable/#atom-tag" rel="alternate"/><published>2010-12-05T18:34:00+00:00</published><updated>2010-12-05T18:34:00+00:00</updated><id>https://simonwillison.net/2010/Dec/5/what-are-some-scalable/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;em&gt;My answer to &lt;a href="https://www.quora.com/What-are-some-scalable-OAuth-and-OpenID-server-implementations/answer/Simon-Willison"&gt;What are some scalable OAuth and OpenID server implementations?&lt;/a&gt; on Quora&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Any OAuth library should scale horizontally - I can't see how any one library would be a better choice than another.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/apis"&gt;apis&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openid"&gt;openid&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/servers"&gt;servers&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/web-development"&gt;web-development&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/quora"&gt;quora&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="apis"/><category term="oauth"/><category term="openid"/><category term="servers"/><category term="web-development"/><category term="quora"/></entry><entry><title>How do you correctly send the oauth_verifier parameter using python-oauth2 and the Twitter API?</title><link href="https://simonwillison.net/2010/Dec/5/how-do-you-correctly/#atom-tag" rel="alternate"/><published>2010-12-05T17:11:00+00:00</published><updated>2010-12-05T17:11:00+00:00</updated><id>https://simonwillison.net/2010/Dec/5/how-do-you-correctly/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;em&gt;My answer to &lt;a href="https://www.quora.com/How-do-you-correctly-send-the-oauth_verifier-parameter-using-python-oauth2-and-the-Twitter-API/answer/Simon-Willison"&gt;How do you correctly send the oauth_verifier parameter using python-oauth2 and the Twitter API?&lt;/a&gt; on Quora&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This seems relevant: &lt;span&gt;&lt;a href="http://groups.google.com/group/twitter-api-announce/tree/browse_frm/thread/472500cfe9e7cdb9/37b02c1092f9deac"&gt;http://groups.google.com/group/t...&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Aha! I think I've solved it. Twitter doesn't send the oauth_verifier argument unless you specify an oauth_callback when requesting the request token.&lt;/p&gt;

&lt;p&gt;Here's a related discussion:&lt;/p&gt;

&lt;span&gt;&lt;a href="https://github.com/simplegeo/python-oauth2/issues#issue/10"&gt;https://github.com/simplegeo/pyt...&lt;/a&gt;&lt;/span&gt;

&lt;p&gt;So, my solution was to use this:&lt;/p&gt;

&lt;p&gt;    resp, content = client.request(request_token_url, "POST",&lt;br /&gt;        body = 'oauth_callback=&lt;span&gt;&lt;a href="http://lanyrd.com/twitter/done/'"&gt;http://lanyrd.com/twitter/done/'&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;    )&lt;/p&gt;

&lt;p&gt;And then later, in my callback function:&lt;/p&gt;

&lt;p&gt;    if 'oauth_verifier' in request.GET:&lt;br /&gt;        token.set_verifier(request.GET['oauth_verifier'])&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/twitter"&gt;twitter&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/quora"&gt;quora&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="oauth"/><category term="twitter"/><category term="quora"/></entry><entry><title>Are there any well-known websites that use Facebook connect or Twitter OAuth as the only sign-in solution without its own sign-in password?</title><link href="https://simonwillison.net/2010/Dec/5/are-there-any-well-known/#atom-tag" rel="alternate"/><published>2010-12-05T13:27:00+00:00</published><updated>2010-12-05T13:27:00+00:00</updated><id>https://simonwillison.net/2010/Dec/5/are-there-any-well-known/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;em&gt;My answer to &lt;a href="https://www.quora.com/Are-there-any-well-known-websites-that-use-Facebook-connect-or-Twitter-OAuth-as-the-only-sign-in-solution-without-its-own-sign-in-password/answer/Simon-Willison"&gt;Are there any well-known websites that use Facebook connect or Twitter OAuth as the only sign-in solution without its own sign-in password?&lt;/a&gt; on Quora&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Our site &lt;span&gt;&lt;a href="http://lanyrd.com/"&gt;http://lanyrd.com/&lt;/a&gt;&lt;/span&gt; only accepts Twitter OAuth logins (at least for the moment).&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/facebook"&gt;facebook&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/twitter"&gt;twitter&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/quora"&gt;quora&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="facebook"/><category term="oauth"/><category term="twitter"/><category term="quora"/></entry><entry><title>RasterWeb: Lanyrd</title><link href="https://simonwillison.net/2010/Aug/31/rasterweb/#atom-tag" rel="alternate"/><published>2010-08-31T20:49:00+00:00</published><updated>2010-08-31T20:49:00+00:00</updated><id>https://simonwillison.net/2010/Aug/31/rasterweb/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://rasterweb.net/raster/2010/08/31/lanyrd/"&gt;RasterWeb: Lanyrd&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Pete Prodoehl calls me out on Lanyrd’s integration with the Twitter auth API at the expense of OpenID. I’ve posted a comment with my justification—essentially, tying to Twitter’s ecosystem means I can actually implement the features I’ve been talking about building on top of OpenID for years, with far less engineering effort.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/identity"&gt;identity&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openid"&gt;openid&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/twitter"&gt;twitter&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/recovered"&gt;recovered&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pete-prodoehl"&gt;pete-prodoehl&lt;/a&gt;&lt;/p&gt;



</summary><category term="identity"/><category term="oauth"/><category term="openid"/><category term="twitter"/><category term="recovered"/><category term="pete-prodoehl"/></entry><entry><title>simplegeo's python-oauth2</title><link href="https://simonwillison.net/2010/Jul/18/simplegeos/#atom-tag" rel="alternate"/><published>2010-07-18T17:22:00+00:00</published><updated>2010-07-18T17:22:00+00:00</updated><id>https://simonwillison.net/2010/Jul/18/simplegeos/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://github.com/simplegeo/python-oauth2"&gt;simplegeo&amp;#x27;s python-oauth2&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
The Python OAuth library scene is frighteningly complicated at the moment. This seems to be the most actively maintained, and the readme includes working example code for talking to the Twitter API (including integration with Django auth).


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/twitter"&gt;twitter&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/recovered"&gt;recovered&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/simplegeo"&gt;simplegeo&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth2"&gt;oauth2&lt;/a&gt;&lt;/p&gt;



</summary><category term="django"/><category term="oauth"/><category term="python"/><category term="twitter"/><category term="recovered"/><category term="simplegeo"/><category term="oauth2"/></entry><entry><title>App Engine at Google I/O 2010</title><link href="https://simonwillison.net/2010/May/20/appengine/#atom-tag" rel="alternate"/><published>2010-05-20T15:30:00+00:00</published><updated>2010-05-20T15:30:00+00:00</updated><id>https://simonwillison.net/2010/May/20/appengine/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://googleappengine.blogspot.com/2010/05/app-engine-at-google-io-2010.html?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A GoogleAppEngineBlog %28Google App Engine Blog%29"&gt;App Engine at Google I/O 2010&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
OpenID and OAuth are now baked in to the AppEngine users API. They’re also demoing two very exciting new features—a mapper API for doing map/reduce style queries against the data store, and a Channel API for building comet applications.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/comet"&gt;comet&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/google"&gt;google&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/google-app-engine"&gt;google-app-engine&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/mapreduce"&gt;mapreduce&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openid"&gt;openid&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/google-io"&gt;google-io&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/recovered"&gt;recovered&lt;/a&gt;&lt;/p&gt;



</summary><category term="comet"/><category term="google"/><category term="google-app-engine"/><category term="mapreduce"/><category term="oauth"/><category term="openid"/><category term="google-io"/><category term="recovered"/></entry><entry><title>RFC5785: Defining Well-Known Uniform Resource Identifiers</title><link href="https://simonwillison.net/2010/Apr/11/rfc/#atom-tag" rel="alternate"/><published>2010-04-11T19:32:28+00:00</published><updated>2010-04-11T19:32:28+00:00</updated><id>https://simonwillison.net/2010/Apr/11/rfc/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.rfc-editor.org/rfc/rfc5785.txt"&gt;RFC5785: Defining Well-Known Uniform Resource Identifiers&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Sounds like a very good idea to me: defining a common prefix of /.well-known/ for well-known URLs (common metadata like robots.txt) and establishing a registry for all such files. OAuth, OpenID and other decentralised identity systems can all benefit from this.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="http://www.mnot.net/blog/2010/04/07/well-known"&gt;Mark Nottingham&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openid"&gt;openid&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rfc"&gt;rfc&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/robots-txt"&gt;robots-txt&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/urls"&gt;urls&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/wellknownurls"&gt;wellknownurls&lt;/a&gt;&lt;/p&gt;



</summary><category term="oauth"/><category term="openid"/><category term="rfc"/><category term="robots-txt"/><category term="urls"/><category term="wellknownurls"/></entry><entry><title>OpenID: Now more powerful and easier to use!</title><link href="https://simonwillison.net/2009/Sep/25/hybrid/#atom-tag" rel="alternate"/><published>2009-09-25T21:08:21+00:00</published><updated>2009-09-25T21:08:21+00:00</updated><id>https://simonwillison.net/2009/Sep/25/hybrid/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://openid.net/2009/09/25/more-powerful-and-easier-to-use/"&gt;OpenID: Now more powerful and easier to use!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
The OpenID+OAuth hybrid protocol (where a user can sign in with OpenID and grant an application access to their OAuth protected resources such as a contact list at the same time) is now supported by Google, Yahoo! and MySpace—this feels like OpenID finally coming of age.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/google"&gt;google&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/hybrid"&gt;hybrid&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/identity"&gt;identity&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/myspace"&gt;myspace&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openid"&gt;openid&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/yahoo"&gt;yahoo&lt;/a&gt;&lt;/p&gt;



</summary><category term="google"/><category term="hybrid"/><category term="identity"/><category term="myspace"/><category term="oauth"/><category term="openid"/><category term="yahoo"/></entry><entry><title>Exploring OAuth-Protected APIs</title><link href="https://simonwillison.net/2009/Aug/23/oauth/#atom-tag" rel="alternate"/><published>2009-08-23T11:06:42+00:00</published><updated>2009-08-23T11:06:42+00:00</updated><id>https://simonwillison.net/2009/Aug/23/oauth/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://mojodna.net/2009/08/21/exploring-oauth-protected-apis.html"&gt;Exploring OAuth-Protected APIs&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
One of the downsides of OAuth is that it makes debugging APIs in your browser much harder. Seth Fitzsimmons’ oauth-proxy solves this by running a Twisted-powered proxy on your local machine which OAuth-signs every request going through it using your consumer key, secret and tokens for that API. Using it with a browsers risks exposing your key and token (but not secret) to sites you accidentally browse to—it would be useful if you could pass a whitelist of API domains as a command line option to the proxy.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/apis"&gt;apis&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/proxies"&gt;proxies&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/seth-fitzsimmons"&gt;seth-fitzsimmons&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/twisted"&gt;twisted&lt;/a&gt;&lt;/p&gt;



</summary><category term="apis"/><category term="oauth"/><category term="proxies"/><category term="python"/><category term="seth-fitzsimmons"/><category term="twisted"/></entry><entry><title>Why an OAuth iframe is a Great Idea</title><link href="https://simonwillison.net/2009/Jul/16/oauth/#atom-tag" rel="alternate"/><published>2009-07-16T20:29:18+00:00</published><updated>2009-07-16T20:29:18+00:00</updated><id>https://simonwillison.net/2009/Jul/16/oauth/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://drstarcat.com/archives/133"&gt;Why an OAuth iframe is a Great Idea&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Because users should a) learn to be phished and b) not even be given the option to avoid being phished if they know what they’re doing? No, no and thrice no. If you want to improve the experience, use a popup window so the user can still see the site they are signing in to in the background.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/iframes"&gt;iframes&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/phishing"&gt;phishing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;&lt;/p&gt;



</summary><category term="iframes"/><category term="oauth"/><category term="phishing"/><category term="security"/></entry><entry><title>Teaching users to be secure is a shared responsibility</title><link href="https://simonwillison.net/2009/Jul/16/responsibility/#atom-tag" rel="alternate"/><published>2009-07-16T20:04:45+00:00</published><updated>2009-07-16T20:04:45+00:00</updated><id>https://simonwillison.net/2009/Jul/16/responsibility/#atom-tag</id><summary type="html">
    &lt;p&gt;Ryan Janssen: &lt;a href="http://drstarcat.com/archives/133"&gt;Why an OAuth iframe is a Great Idea&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote cite="http://drstarcat.com/archives/133"&gt;&lt;p&gt;The reason the OAuth community prefers that we open up a new window is that if you look at the URL in the window (the place you type in a site’s name), you would see that it says www.netflix.com* and know that you are giving your credentials to Netflix.&lt;/p&gt;

&lt;p&gt;Or would you?  I would!  Other technologists would!  But would you?  Would you even notice?  If you noticed would you care?  The answer for the VAST majority of the world is of course, no.  In fact to an average person, getting taken to an ENTIRELY other site with some weird little dialog floating in a big page is EXTREMELY suspicious.  The real site you are trusting to do the right thing is SetJam (not weird pop-up window site).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I posted a reply comment on that post, but I'll replicate it in full here:&lt;/p&gt;

&lt;blockquote cite="http://drstarcat.com/archives/133#IDComment27455126"&gt;
&lt;p&gt;Please, please don't do this.&lt;/p&gt;

&lt;p&gt;As web developers we have a shared responsibility to help our users stay safe on the internet. This is becoming ever more important as people move more of their lives online.&lt;/p&gt;

&lt;p&gt;It's an almost sisyphean task. If you want to avoid online fraud, you need to understand an enormous stack of technologies: browsers, web pages, links, URLs, DNS, SSL, certificates... I know user education is never the right answer, but in the case of the Web I honestly can't see any other route.&lt;/p&gt;

&lt;p&gt;The last thing we need is developers making the problem worse by encouraging unsafe behaviour. That was the whole POINT of OAuth - the password anti-pattern was showing up everywhere, and was causing very real problems. OAuth provides an alternative, but we still have a long way to go convincing users not to hand their password over to any site that asks for it. Still, it's a small victory in a much bigger war.&lt;/p&gt;

&lt;p&gt;If developers start showing OAuth in an iframe, that victory was for nothing - we may as well not have bothered. OAuth isn't just a protocol, it's an ambitious attempt to help users understand the importance of protecting their credentials, and the fact that different sites should be granted different permissions with regards to accessing their stuff. This is a difficult but critical lesson for users to learn. The only real hope is if OAuth, implemented correctly, spreads far enough around the Web that people start to understand it and get a feel for how it is meant to work.&lt;/p&gt;

&lt;p&gt;By implementing OAuth in an iframe you are completely undermining this effort - and in doing so you're contributing to a tragedy of the commons where selfish behaviour on the behalf of a few causes problems for everyone else. Even worse, if the usability DOES prove to be better (which wouldn't be surprising) you'll be actively encouraging people to implement OAuth in an insecure way - your competitors will hardly want to keep doing things the secure way if you are getting higher conversion rates than they are.&lt;/p&gt;

&lt;p&gt;So once again, please don't do this.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I hope my argument is convincing. In case it isn't, I'd strongly suggest that any sites offering OAuth protected APIs add frame-busting JavaScript to their OAuth verification pages. Thankfully, in this case there's a technical option for protecting the commons.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; It turns out Netflix already use a frame-busting script on their OAuth authentication page.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/education"&gt;education&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/framebusting"&gt;framebusting&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/iframes"&gt;iframes&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/phishing"&gt;phishing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/responsibility"&gt;responsibility&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="education"/><category term="framebusting"/><category term="iframes"/><category term="oauth"/><category term="phishing"/><category term="responsibility"/><category term="security"/></entry><entry><title>oauth-signpost</title><link href="https://simonwillison.net/2009/May/7/oauthsignpost/#atom-tag" rel="alternate"/><published>2009-05-07T07:33:00+00:00</published><updated>2009-05-07T07:33:00+00:00</updated><id>https://simonwillison.net/2009/May/7/oauthsignpost/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://code.google.com/p/oauth-signpost/"&gt;oauth-signpost&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
The Qype API uses OAuth to sign client requests with the developer’s API key, so it’s not surprising to see them release a Java OAuth signing library compatible with Google’s Android mobile platform.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/android"&gt;android&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/api-keys"&gt;api-keys&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/java"&gt;java&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/qype"&gt;qype&lt;/a&gt;&lt;/p&gt;



</summary><category term="android"/><category term="api-keys"/><category term="java"/><category term="oauth"/><category term="qype"/></entry><entry><title>django-piston</title><link href="https://simonwillison.net/2009/Apr/30/jespern/#atom-tag" rel="alternate"/><published>2009-04-30T19:55:15+00:00</published><updated>2009-04-30T19:55:15+00:00</updated><id>https://simonwillison.net/2009/Apr/30/jespern/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://bitbucket.org/jespern/django-piston/wiki/Home"&gt;django-piston&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Promising looking Django mini-framework for creating RESTful APIs, from the bitbucket team. Ticks all of Jacob’s boxes, even including built-in pluggable authentication support with HTTP Basic, Digest and OAuth out of the box.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/apis"&gt;apis&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/authentication"&gt;authentication&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/bitbucket"&gt;bitbucket&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/digest"&gt;digest&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jespernoehr"&gt;jespernoehr&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/piston"&gt;piston&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rest"&gt;rest&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/restful"&gt;restful&lt;/a&gt;&lt;/p&gt;



</summary><category term="apis"/><category term="authentication"/><category term="bitbucket"/><category term="digest"/><category term="django"/><category term="jespernoehr"/><category term="oauth"/><category term="piston"/><category term="python"/><category term="rest"/><category term="restful"/></entry><entry><title>Sign in with Twitter</title><link href="https://simonwillison.net/2009/Apr/20/twitter/#atom-tag" rel="alternate"/><published>2009-04-20T04:10:33+00:00</published><updated>2009-04-20T04:10:33+00:00</updated><id>https://simonwillison.net/2009/Apr/20/twitter/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://apiwiki.twitter.com/Sign-in-with-Twitter"&gt;Sign in with Twitter&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Intriguing: Twitter are now an OpenID-style identity provider... using OAuth.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openid"&gt;openid&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/twitter"&gt;twitter&lt;/a&gt;&lt;/p&gt;



</summary><category term="oauth"/><category term="openid"/><category term="twitter"/></entry><entry><title>Quoting Blaine Cook</title><link href="https://simonwillison.net/2009/Jan/6/blaine/#atom-tag" rel="alternate"/><published>2009-01-06T09:37:59+00:00</published><updated>2009-01-06T09:37:59+00:00</updated><id>https://simonwillison.net/2009/Jan/6/blaine/#atom-tag</id><summary type="html">
    &lt;blockquote cite="http://simonwillison.net/2009/Jan/2/adactio/#c42975"&gt;&lt;p&gt;As more details become available, it seems what happened is that a Twitter administrator (i.e., employee) gave their password to a 3rd party site because their API requires it, which was then used to compromise Twitter's admin interface.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="http://simonwillison.net/2009/Jan/2/adactio/#c42975"&gt;Blaine Cook&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/twitter"&gt;twitter&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;&lt;/p&gt;



</summary><category term="oauth"/><category term="twitter"/><category term="security"/></entry><entry><title>Quoting Alex Payne</title><link href="https://simonwillison.net/2009/Jan/5/antipatterns/#atom-tag" rel="alternate"/><published>2009-01-05T10:47:41+00:00</published><updated>2009-01-05T10:47:41+00:00</updated><id>https://simonwillison.net/2009/Jan/5/antipatterns/#atom-tag</id><summary type="html">
    &lt;blockquote cite="http://simonwillison.net/2009/Jan/2/adactio/#c42956"&gt;&lt;p&gt;The username/password key's major disadvantage is that it open all the doors to the house. The OAuth key only opens a couple doors; the scope of the credentials is limited. That's a benefit, to be sure, but in Twitter's case, a malicious application that registered for OAuth with both read and write privileges can do most evil things a user might be worried about.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="http://simonwillison.net/2009/Jan/2/adactio/#c42956"&gt;Alex Payne&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/phishing"&gt;phishing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/alex-payne"&gt;alex-payne&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/twitter"&gt;twitter&lt;/a&gt;&lt;/p&gt;



</summary><category term="phishing"/><category term="alex-payne"/><category term="oauth"/><category term="security"/><category term="twitter"/></entry><entry><title>Antipatterns for sale</title><link href="https://simonwillison.net/2009/Jan/2/adactio/#atom-tag" rel="alternate"/><published>2009-01-02T10:48:17+00:00</published><updated>2009-01-02T10:48:17+00:00</updated><id>https://simonwillison.net/2009/Jan/2/adactio/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://adactio.com/journal/1538"&gt;Antipatterns for sale&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Twply collected over 800 Twitter usernames and passwords (OAuth can’t arrive soon enough) and was promptly auctioned off on SitePoint to the highest bidder.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/jeremy-keith"&gt;jeremy-keith&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/passwordantipattern"&gt;passwordantipattern&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/passwords"&gt;passwords&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sitepoint"&gt;sitepoint&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/twitter"&gt;twitter&lt;/a&gt;&lt;/p&gt;



</summary><category term="jeremy-keith"/><category term="oauth"/><category term="passwordantipattern"/><category term="passwords"/><category term="security"/><category term="sitepoint"/><category term="twitter"/></entry><entry><title>Now You Can Sign Into Friend Connect Sites With Your Twitter ID</title><link href="https://simonwillison.net/2008/Dec/15/ffs/#atom-tag" rel="alternate"/><published>2008-12-15T17:20:08+00:00</published><updated>2008-12-15T17:20:08+00:00</updated><id>https://simonwillison.net/2008/Dec/15/ffs/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.techcrunch.com/2008/12/15/now-you-can-sign-into-friend-connect-sites-with-your-twitter-id/"&gt;Now You Can Sign Into Friend Connect Sites With Your Twitter ID&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Great. Now even Google is asking me for my Twitter password. Slow clap. How’s that Twitter OAuth beta coming along?


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/google"&gt;google&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/passwordantipattern"&gt;passwordantipattern&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/twitter"&gt;twitter&lt;/a&gt;&lt;/p&gt;



</summary><category term="google"/><category term="oauth"/><category term="passwordantipattern"/><category term="security"/><category term="twitter"/></entry><entry><title>Skillswap goes Portable</title><link href="https://simonwillison.net/2008/Nov/21/skillswap/#atom-tag" rel="alternate"/><published>2008-11-21T10:25:56+00:00</published><updated>2008-11-21T10:25:56+00:00</updated><id>https://simonwillison.net/2008/Nov/21/skillswap/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://icanhaz.com/skillswapgoesportable"&gt;Skillswap goes Portable&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Skillswap Brighton will be addressing OAuth and Data Portability on Wednesday. I’m annoyed to be missing it.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/brighton"&gt;brighton&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/data-portability"&gt;data-portability&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/events"&gt;events&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/oauth"&gt;oauth&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/skillswap"&gt;skillswap&lt;/a&gt;&lt;/p&gt;



</summary><category term="brighton"/><category term="data-portability"/><category term="events"/><category term="oauth"/><category term="skillswap"/></entry></feed>