<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/rss-style.xsl" type="text/xsl"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	    xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	     xmlns:dc="http://purl.org/dc/elements/1.1/"
	   xmlns:atom="http://www.w3.org/2005/Atom"
	     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	  xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>
<channel>
	<title>oauth &#8211; Terence Eden’s Blog</title>
	<atom:link href="https://shkspr.mobi/blog/tag/oauth/feed/" rel="self" type="application/rss+xml" />
	<link>https://shkspr.mobi/blog</link>
	<description>Regular nonsense about tech and its effects 🙃</description>
	<lastBuildDate>Fri, 20 Feb 2026 10:41:43 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://shkspr.mobi/blog/wp-content/uploads/2023/07/cropped-avatar-32x32.jpeg</url>
	<title>oauth &#8211; Terence Eden’s Blog</title>
	<link>https://shkspr.mobi/blog</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title><![CDATA[Adding OpenStreetMap login to Auth0]]></title>
		<link>https://shkspr.mobi/blog/2026/02/adding-openstreetmap-login-to-auth0/</link>
					<comments>https://shkspr.mobi/blog/2026/02/adding-openstreetmap-login-to-auth0/#respond</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Tue, 24 Feb 2026 12:34:21 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[Auth0]]></category>
		<category><![CDATA[developers]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[OpenStreetMap]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=67593</guid>

					<description><![CDATA[So you want to add OSM as an OAuth provider to Auth0? Here&#039;s a tip - you do not want to create a custom social connection!  Instead, you need to create an &#34;OpenID Connect&#34; provider. Here&#039;s how.  OpenSteetMap  As per the OAuth documentation you will need to:   Register a new app at https://www.openstreetmap.org/oauth2/applications/ Give it a name that users will recognise Give it a redirect of…]]></description>
										<content:encoded><![CDATA[<p>So you want to add OSM as an OAuth provider to Auth0? Here's a tip - you do <em>not</em> want to create a custom social connection!</p>

<p>Instead, you need to create an "OpenID Connect" provider. Here's how.</p>

<h2 id="opensteetmap"><a href="https://shkspr.mobi/blog/2026/02/adding-openstreetmap-login-to-auth0/#opensteetmap">OpenSteetMap</a></h2>

<p>As per <a href="https://wiki.openstreetmap.org/wiki/OAuth#Using_OpenStreetMap_as_identity_provider">the OAuth documentation</a> you will need to:</p>

<ul>
<li>Register a new app at <a href="https://www.openstreetmap.org/oauth2/applications/">https://www.openstreetmap.org/oauth2/applications/</a></li>
<li>Give it a name that users will recognise</li>
<li>Give it a redirect of <code>https://Your Auth0 Tenant.eu.auth0.com/login/callback</code></li>
<li>Tick the box for "Sign in using OpenStreetMap"</li>
</ul>

<p>Once created, you will need to securely save your Client ID and Client Secret.</p>

<h2 id="auth0"><a href="https://shkspr.mobi/blog/2026/02/adding-openstreetmap-login-to-auth0/#auth0">Auth0</a></h2>

<p>These options change frequently, so use this guide with care.</p>

<ul>
<li>Once you have logged in to your Auth0 Tennant, go to Authentication → Enterprise → OpenID Connect → Create Connection</li>
<li>Provide the new connection with the Client ID and Client Secret</li>
<li>Set the "scope" to be <code>openid</code></li>
<li>Set the OpenID Connect Discovery URL to be <code>https://www.openstreetmap.org/.well-known/openid-configuration</code></li>
<li>In the "Login Experience" tick the box for "Display connection as a button"</li>
<li>Set the favicon to be <code>https://blog.openstreetmap.org/wp-content/uploads/2022/07/osm-favicon.png</code> or other suitable graphic</li>
</ul>

<h2 id="next-steps"><a href="https://shkspr.mobi/blog/2026/02/adding-openstreetmap-login-to-auth0/#next-steps">Next Steps</a></h2>

<p>We're not quite done, sadly.</p>

<p>The details which OSM sends back to Auth0 are limited, so Auth0 is missing a few bits:</p>

<pre><code class="language-json">{
    "created_at": "2026-02-29T12:34:56.772Z",
    "identities": [
        {
            "user_id": "openstreetmap-openid|123456",
            "provider": "oidc",
            "connection": "openstreetmap-openid",
            "isSocial": false
        }
    ],
    "name": "",
    "nickname": "",
    "picture": "https://cdn.auth0.com/avatars/default.png",
    "preferred_username": "Terence Eden",
    "updated_at": "2026-02-04T12:01:33.772Z",
    "user_id": "oidc|openstreetmap-openid|123456",
    "last_ip": "12.34.56.78",
    "last_login": "2026-02-29T12:34:56.772Z",
    "logins_count": 1,
    "blocked_for": [],
    "guardian_authenticators": [],
    "passkeys": []
}
</code></pre>

<p>Annoyingly, Auth0 doesn't set a name or nickname - so you'll need to manually get the <code>preferred_username</code>, or create a "User Map":</p>

<pre><code class="language-json">{
  "mapping_mode": "use_map",
  "attributes": {
    "nickname": "${context.tokenset.preferred_username}",
    "name":     "${context.tokenset.preferred_username}"
  }
}
</code></pre>

<p>There's also no avatar image - only the default one.</p>

<h3 id="getting-the-avatar-image"><a href="https://shkspr.mobi/blog/2026/02/adding-openstreetmap-login-to-auth0/#getting-the-avatar-image">Getting the Avatar Image</a></h3>

<p>The <a href="https://wiki.openstreetmap.org/wiki/API_v0.6">OSM API</a> has a method for <a href="https://wiki.openstreetmap.org/wiki/API_v0.6#Methods_for_user_data">getting user data</a>.</p>

<p>For example, here's all my public data: <a href="https://api.openstreetmap.org/api/0.6/user/98672.json">https://api.openstreetmap.org/api/0.6/user/98672.json</a> - thankfully no authorisation required!</p>

<pre><code class="language-json">{
  "user": {
    "id": 98672,
    "display_name": "Terence Eden",
    "img": {
      "href": "https://www.gravatar.com/avatar/52cb49a66755f31abf4df9a6549f0f9c.jpg?s=100&amp;d=https%3A%2F%2Fapi.openstreetmap.org%2Fassets%2Favatar_large-54d681ddaf47c4181b05dbfae378dc0201b393bbad3ff0e68143c3d5f3880ace.png"
    }
  }
}
</code></pre>

<p>Alternatively, you can <a href="https://github.com/microlinkhq/unavatar/issues/488">use the Unavatar service</a> to get the image indirectly.</p>

<p>I hope that's helpful to someone!</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=67593&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2026/02/adding-openstreetmap-login-to-auth0/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Add a custom icon to Auth0's Custom Social integrations]]></title>
		<link>https://shkspr.mobi/blog/2024/12/add-a-custom-icon-to-auth0s-custom-social-integrations/</link>
					<comments>https://shkspr.mobi/blog/2024/12/add-a-custom-icon-to-auth0s-custom-social-integrations/#respond</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Mon, 09 Dec 2024 12:34:56 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[Auth0]]></category>
		<category><![CDATA[HowTo]]></category>
		<category><![CDATA[oauth]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=54309</guid>

					<description><![CDATA[This is so fucking stupid.  There is no way to update the logo of a custom social connection on Auth0 without using the command line.  On literally every other service I&#039;ve used, there&#039;s a little box to upload a logo. But Okta have a funny idea of what developers want.  And, to make matters worse, their documentation contains an error! They don&#039;t listen to community requests or take bug reports,…]]></description>
										<content:encoded><![CDATA[<p>This is <em>so</em> fucking stupid.</p>

<p>There is no way to update the logo of a custom social connection on Auth0 without using the command line.  On literally every other service I've used, there's a little box to upload a logo. But Okta have a funny idea of what developers want.</p>

<p>And, to make matters worse, <a href="https://auth0.com/docs/authenticate/identity-providers/social-identity-providers/oauth2">their documentation contains an error</a>! They don't listen to community requests or take bug reports, so I'm blogging in the hope that this is useful to you.</p>

<h2 id="the-command"><a href="https://shkspr.mobi/blog/2024/12/add-a-custom-icon-to-auth0s-custom-social-integrations/#the-command">The Command</a></h2>

<pre><code class="language-bash">curl --request PATCH \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer eyJhb...ZEQ' \
  --url 'https://whatever.eu.auth0.com/api/v2/connections/con_qwerty123456' \
  --data ' ... '
</code></pre>

<p>You will also need to supply some JSON in the <code>data</code> parameter. I've formatted it to be easier to read than the garbage documentation. <em>All</em> of these fields are mandatory.</p>

<pre><code class="language-json">{
  "options": {
    "client_id": "your-app-id",
    "client_secret": "Shhhhhh!",
    "icon_url": "https://example.com/image.svg",
    "scripts": {
      "fetchUserProfile": "???"
    },
    "authorizationURL": "https://example.com/oauth2/authorize",
    "tokenURL": "https://example.com/oauth2/token",
    "scope": "auth"
  },
  "display_name": "Whatever"
}
</code></pre>

<p>OK, but how do you get all those values?</p>

<ul>
<li>Bearer token:

<ul>
<li><a href="https://auth0.com/docs/secure/tokens/access-tokens/management-api-access-tokens">Create a management token</a></li>
<li>The only scope it needs is <code>update:connections</code></li>
</ul></li>
<li>URl

<ul>
<li>This is your normal Auth0 domain name.</li>
<li>The Connection ID at the end can be found in the dashboard of your social connection<br><img src="https://shkspr.mobi/blog/wp-content/uploads/2024/11/social-fs8.png" alt="Screenshot showing an ID field." width="800" height="211" class="aligncenter size-full wp-image-54310"></li>
</ul></li>
<li>Client ID &amp; Secret

<ul>
<li>You set these in the social connection's dashboard.</li>
</ul></li>
<li><code>icon_url</code>

<ul>
<li>Public link to an image. It can be an SVG.</li>
</ul></li>
<li><code>fetchUserProfile</code>

<ul>
<li>Whatever code you want to run. If you don't want any, you can't leave it blank. So type in a couple of characters.</li>
</ul></li>
<li><code>authorizationURL</code> and <code>tokenURL</code>

<ul>
<li>Wherever you want to redirect users to</li>
</ul></li>
<li><code>display_name</code>

<ul>
<li>What you want to show to the user</li>
</ul></li>
</ul>

<p>This is <em>such</em> a load of bollocks! Is it really that hard for the Okta team to put an input field with "type the URl of your logo"?</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=54309&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2024/12/add-a-custom-icon-to-auth0s-custom-social-integrations/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Creating a generic "Log-in with Mastodon" service]]></title>
		<link>https://shkspr.mobi/blog/2024/12/creating-a-generic-log-in-with-mastodon-service/</link>
					<comments>https://shkspr.mobi/blog/2024/12/creating-a-generic-log-in-with-mastodon-service/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sun, 08 Dec 2024 12:34:47 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[Auth0]]></category>
		<category><![CDATA[MastodonAPI]]></category>
		<category><![CDATA[oauth]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=54287</guid>

					<description><![CDATA[Let&#039;s say you have a website - your_website.tld - and you want people to log in to it using their Mastodon account.  For a traditional social-media site like Twitter or Facebook, you would create an OAuth app on the service that you want. But there are hundreds of Mastodon servers. So you need to create a new app for each one.  That sounds hard, but it isn&#039;t.  Well… not too hard.  Here&#039;s some c…]]></description>
										<content:encoded><![CDATA[<p>Let's say you have a website - <code>your_website.tld</code> - and you want people to log in to it using their Mastodon account.</p>

<p>For a traditional social-media site like Twitter or Facebook, you would create an OAuth app on the service that you want. But there are <em>hundreds</em> of Mastodon servers. So you need to create a new app for each one.  That sounds hard, but it isn't.  Well… not <em>too</em> hard.</p>

<p>Here's some <a href="https://infosec.press/jerry/how-to-user-mastodons-built-on-oauth-provider-as-the-authentication-provider">code adapted from Infosec.press</a>.  It's all written using cURL on the command line - so you should be able to adapt it to your preferred programming language.</p>

<h2 id="register-an-app-on-the-users-mastodon-instance"><a href="https://shkspr.mobi/blog/2024/12/creating-a-generic-log-in-with-mastodon-service/#register-an-app-on-the-users-mastodon-instance">Register an app on the user's Mastodon instance</a></h2>

<p>Let's assume the user has given you the name of their Mastodon server - <code>example.social</code></p>

<p>You then send a request for an app to be created on <code>example.social</code> with your website's details. All it requests is the ability to read a user's details, nothing else.</p>

<pre><code class="language-bash">curl -X POST \
 -F "client_name=Login to your_website.tld" \
 -F "redirect_uris=https://your_website.tld/oauth/mastodon?server=example.social&amp;" \
 -F "scopes=read:accounts" \
 -F "website=https://your_website.tld" \
 -A "user-agent/0.1"
 https://example.social/api/v1/apps
</code></pre>

<p>You can set the User Agent to be anything suitable. Some servers won't work if it is omitted.</p>

<p>If the request was successful, <code>example.social</code> will send you this JSON in response:</p>

<pre><code class="language-json">{
  "id": "12345",
  "name": "Login to your_website.tld",
  "website": "https://your_website.tld",
  "scopes": [
    "read:accounts"
  ],
  "redirect_uris": [
    "https://your_website.tld/oauth/mastodon?server=example.social&amp;"
  ],
  "vapid_key": "qwertyuiop-asdfghjkl-zxcvbnm",
  "redirect_uri": "https://your_website.tld/oauth/mastodon?server=example.social&amp;",
  "client_id": "qw_asdfghjkl_zxcvbnm",
  "client_secret": "qwertyuiop1234567890"
}
</code></pre>

<p>Save the server's address, the <code>client_id</code>, and the <code>client_secret</code>. You will need all three later.</p>

<h2 id="the-user-logs-in-to-their-mastodon-instance"><a href="https://shkspr.mobi/blog/2024/12/creating-a-generic-log-in-with-mastodon-service/#the-user-logs-in-to-their-mastodon-instance">The user logs in to their Mastodon instance</a></h2>

<p>You need to redirect the user to their server so they can log in. You need to construct a Mastodon URl using the data you received back. Don't forget to URl encode the <code>redirect_uri</code>.</p>

<p>For example, redirect the user to:</p>

<pre><code class="language-_">https://example.social/oauth/authorize
?client_id=qw_asdfghjkl_zxcvbnm
&amp;scope=read:accounts
&amp;redirect_uri=https://your_website.tld/oauth/mastodon%3Fserver=example.social%26
&amp;response_type=code
</code></pre>

<p>When the user visits that URl they can then log in. If they're successful, they'll be redirected back to your server using your specified redirect URI:</p>

<pre><code class="language-_">https://your_website.tld/oauth/mastodon?server=example.social&amp;code=qazwsxedcrfvtgbyhnujm
</code></pre>

<h2 id="get-a-bearer-token"><a href="https://shkspr.mobi/blog/2024/12/creating-a-generic-log-in-with-mastodon-service/#get-a-bearer-token">Get a Bearer token</a></h2>

<p>Your website has received a GET request with the user's server name and an authorisation code. As per <a href="https://docs.joinmastodon.org/client/authorized/#token">the Mastodon documentation</a>, your app uses that code to request a Bearer token:</p>

<pre><code class="language-bash">curl -X POST \
 -F "client_id=qw_asdfghjkl_zxcvbnm" \
 -F "client_secret=qwertyuiop1234567890" \
 -F "redirect_uri=https://your_website.tld/oauth/mastodon?server=example.social&amp;" \
 -F "grant_type=authorization_code" \
 -F "code=qazwsxedcrfvtgbyhnujm" \
 -F "scope=read:accounts" \
 -A "user-agent/0.1"
 https://example.social/oauth/token
</code></pre>

<p>If that's worked, the user's server will return a Bearer token like this:</p>

<pre><code class="language-json">{
    "access_token": "abcdefg_123456",
    "token_type": "Bearer",
    "scope": "read:accounts",
    "created_at": 1732916685
}
</code></pre>

<h2 id="get-the-users-details"><a href="https://shkspr.mobi/blog/2024/12/creating-a-generic-log-in-with-mastodon-service/#get-the-users-details">Get the user's details</a></h2>

<p>Finally(!) you can use that token to verify the user's credentials with the server:</p>

<pre><code class="language-bash">curl \
 -H "Authorization: Bearer abcdefg_123456" \
 -A "user-agent/0.1"
 https://example.social/api/v1/accounts/verify_credentials
</code></pre>

<p>If that works, you'll get back all the user's details. Something like this:</p>

<pre><code class="language-json">{
    "id": "7112",
    "username": "Edent",
    "acct": "Edent",
    "display_name": "Terence Eden",
    "url": "https://mastodon.social/@Edent",
    "avatar": "https://files.mastodon.social/accounts/avatars/000/007/112/original/37df032a5951b96c.jpg",
...
}
</code></pre>

<h2 id="putting-it-all-together"><a href="https://shkspr.mobi/blog/2024/12/creating-a-generic-log-in-with-mastodon-service/#putting-it-all-together">Putting it all together</a></h2>

<ol>
<li>User providers their Mastodon instance's domain name</li>
<li>Your service looks up the domain name in its database

<ul>
<li>If there are no results, request to create a new app on the Mastodon instance and save the returned <code>client_id</code> and <code>client_secret</code></li>
</ul></li>
<li>Redirect the User to their Mastodon instance, using a URl which contains the <code>client_id</code> &amp; callback URl</li>
<li>User logs in to their Mastodon instance</li>
<li>The User's Mastodon instance redirects the User to your service's callback URl which includes an the instance's domain name and User's authorisation code</li>
<li>Your service reads the User's domain name and authorisation code</li>
<li>Your service exchanges those details for a Bearer token</li>
<li>Your service uses the Bearer token to get the User's account details</li>
</ol>

<h2 id="next-steps"><a href="https://shkspr.mobi/blog/2024/12/creating-a-generic-log-in-with-mastodon-service/#next-steps">Next steps?</a></h2>

<p>This basic code works. For my next trick, can I integrate it into Auth0?</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=54287&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2024/12/creating-a-generic-log-in-with-mastodon-service/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[$3k Bug Bounty - Twitter's OAuth Mistakes]]></title>
		<link>https://shkspr.mobi/blog/2018/12/twitter-bug-bounty/</link>
					<comments>https://shkspr.mobi/blog/2018/12/twitter-bug-bounty/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Fri, 14 Dec 2018 12:09:32 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[Bug Bounty]]></category>
		<category><![CDATA[hacking]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[twitter]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=30658</guid>

					<description><![CDATA[Imagine the scenario.  You&#039;re trying out some cool new Twitter app. It asks you to sign in via OAuth as per usual.  You look through the permissions - phew - it doesn&#039;t want to access your Direct Messages.    You authorise it - whereupon it promptly leaks to the world all your sexts, inappropriate jokes, and dank memes. Tragic!  What&#039;s going on?  Many years ago the official Twitter API keys were…]]></description>
										<content:encoded><![CDATA[<p>Imagine the scenario.  You're trying out some cool new Twitter app. It asks you to sign in via OAuth as per usual.  You look through the permissions - <em>phew</em> - it doesn't want to access your Direct Messages.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2018/11/Google-TV-Twitter-DMs-fs8.png" alt="A Twitter login screen. Highlighted is the information that it cannot access your DMs." width="697" height="456" class="aligncenter size-full wp-image-30659">

<p>You authorise it - whereupon it promptly leaks to the world all your sexts, inappropriate jokes, and dank memes. Tragic!</p>

<h2 id="whats-going-on"><a href="https://shkspr.mobi/blog/2018/12/twitter-bug-bounty/#whats-going-on">What's going on?</a></h2>

<p>Many years ago <a href="https://web.archive.org/web/20151112153930/https://gist.github.com/shobotch/5160017">the official Twitter API keys were leaked</a>.  This means that app authors who can't get their app approved by Twitter are still able to access the Twitter API.</p>

<p>For some reason, Twitter's OAuth screen says that these apps do <em>not</em> have access to Direct Messages. But they do!</p>

<p>In short, users could be tricked into allowing access to their DMs.</p>

<h2 id="restrictions"><a href="https://shkspr.mobi/blog/2018/12/twitter-bug-bounty/#restrictions">Restrictions</a></h2>

<p>There are some restrictions which Twitter has put in place in the name of good security. The most important of these is restricting callback addresses. After successful login, the apps will <em>only</em> return to a <em>predefined</em> URL.  That means you can't take the official Twitter keys and send the user to your app.  This is a sensible security decision.</p>

<p>Except... Not every app has a URL. Or supports callbacks. Or is an actual app.  Twitter has a secondary authorisation mechanism for such cases.  You log in, it provides a PIN, you type the PIN into your app.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2018/11/iphone-pin-fs8.png" alt="Twitter login screen displaying a security PIN." width="695" height="243" class="aligncenter size-full wp-image-30660">

<p>It appears that these official PIN apps don't display the correct OAuth information to the user.</p>

<h2 id="fixing-it"><a href="https://shkspr.mobi/blog/2018/12/twitter-bug-bounty/#fixing-it">Fixing it</a></h2>

<p>Will Twitter audit old apps and make sure the permissions are correctly displayed? I hope so!</p>

<p>Ideally, Twitter should have a much more granular permissions model. Allow apps to read DMs, but not send them. Write tweets, but not delete them.  Read Tweets, but not follow people.</p>

<h2 id="timeline"><a href="https://shkspr.mobi/blog/2018/12/twitter-bug-bounty/#timeline">Timeline</a></h2>

<ul>
<li>2018-11-06 Submitted via <a href="https://hackerone.com/bugs?report_id=434763">HackerOne</a></li>
<li>2018-11-06 Provided clarification and PoC. Issue accepted.</li>
<li>2018-11-15 Proposed publication date of 30th November rejected due to US holidays.</li>
<li>2018-11-16 Bug Bounty of $2,940 offered. Filled in the W2 form to say I'm not a US taxpayer.</li>
<li>2018-11-17 <a href="https://untappd.com/user/edent/checkin/676732835">Drank a fair amount of cider</a>.</li>
<li>2018-11-21 £2,287.05 deposited in my UK bank account. There was also the option of receiving it via PayPal.</li>
<li>2018-12-06 Twitter fixed the issue and <a href="https://twitter.com/edent/status/1070810894144339974">published the bounty payout</a>. They let me know I was clear to publish.</li>
<li>2018-12-07 I provided clarification that the issue was still present on some API keys.</li>
<li>2018-12-14 Published this report.</li>
</ul>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=30658&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2018/12/twitter-bug-bounty/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Web Based OAuth Is A Security Nightmare For Apps]]></title>
		<link>https://shkspr.mobi/blog/2015/05/web-based-oauth-is-a-security-nightmare-for-apps/</link>
					<comments>https://shkspr.mobi/blog/2015/05/web-based-oauth-is-a-security-nightmare-for-apps/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Wed, 27 May 2015 10:52:16 +0000</pubDate>
				<category><![CDATA[Security]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[web]]></category>
		<guid isPermaLink="false">https://shkspr.mobi/blog/?p=21073</guid>

					<description><![CDATA[Twitter have just released Periscope for Android.  I&#039;ll do a full review of it later (tl;dr it&#039;s Qik with worse resolution) - but for now, I want to focus on the sign up process.  You can only sign in with Twitter.  That&#039;s fine, it&#039;s a Twitter product.  So I pressed the sign-in button and this is the screen I saw.    Is that the Twitter mobile website embedded into the app or is it a phishing…]]></description>
										<content:encoded><![CDATA[<p>Twitter have just released <a href="https://www.pcmag.com/reviews/twitter-periscope-for-android">Periscope for Android</a>.  I'll do a full review of it later (tl;dr it's Qik with worse resolution) - but for now, I want to focus on the sign up process.</p>

<p>You can only sign in with Twitter.  That's fine, it's a Twitter product.  So I pressed the sign-in button and this is the screen I saw.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2015/05/Periscope-Twitter-Sign-In-fs8.png" alt="Periscope Twitter Sign In-fs8" width="400" height="783" class="aligncenter size-full wp-image-21074">

<p>Is that the Twitter mobile website embedded into the app or is it a phishing page? <strong>I've no way of knowing!</strong></p>

<p>I can't see the URL bar - for all I know, this could be an elaborate forgery.  I have to completely trust that this product is <em>actually</em> provided by Twitter.  In Periscope's case, it probably is.  But this is teaching users a dangerous anti-pattern that the web community has tried <em>so</em> hard to eradicate.  And, no, 2FA doesn't really help us here.</p>

<p>Let's take a step back and look at what the problem is.</p>

<p>In the bad old days, if you downloaded a 3rd party app (for Twitter, Facebook, email, etc) the app would ask you for your username and password.  This is <strong>dangerous</strong>.  You have no idea what the app is doing with your password.  Is it saving it? Selling it to criminals? Silently changing all your settings?  Who knows!</p>

<p>So, we introduce a more secure way of doing things, at the cost of a little more complexity.</p>

<h2 id="oauth"><a href="https://shkspr.mobi/blog/2015/05/web-based-oauth-is-a-security-nightmare-for-apps/#oauth">OAuth</a></h2>

<p>Here's how OAuth works (from a user's point of view - there's a lot more stuff going on in the background!)</p>

<ol>
    <li>Click "Log in with Twitter" (or whichever service)</li>
    <li>Get taken to Twitter's website.</li>
    <li>Login (if you're not already).</li>
    <li>Get redirected back to the app
<ol>
    <li>Ideally the redirect automatically logs you in.</li>
    <li>In some circumstances Twitter gives you a PIN and says "Type this in to the app"</li>
</ol></li>
</ol>

<p>With OAuth you <strong>never</strong> need to give up your password to a random app.</p>

<p>It can be slightly cumbersome - especially if you have to remember a 4 digit PIN to complete the login.  But I'm strongly in favour of educating users not to give out their passwords willy-nilly.</p>

<p>In Periscope's case, the user has to trust that the app hasn't just ripped-off the Twitter website.  There's absolutely no way to verify that it is a genuine and secure login page.</p>

<p>Even if you have 2-Factor Authentication (where Twitter texts you a login code) you're not safe.  Why? Because if the app is intercepting your username and password, it can <em>also</em> intercept your 2FA code.  Sure, it can only use it for a minute or so (<a href="https://shkspr.mobi/blog/2013/09/facebook-2fa-security-flaw-disclosed/">with some restrictions</a>) - but that's enough time to completely take over your account.</p>

<p>As software developers, we <strong>have</strong> to stop encouraging this <a href="http://c2.com/cgi/wiki?AntiPattern">anti-pattern</a>.  Periscope is teaching users that it's OK to type their password into any box which <em>looks</em> like it's authentic.</p>

<h2 id="some-solutions"><a href="https://shkspr.mobi/blog/2015/05/web-based-oauth-is-a-security-nightmare-for-apps/#some-solutions">Some Solutions</a></h2>

<p>Any solution has to make a user leave the untrusted app and use a trusted service.  Sorry, that's just how it is.  You can't delegate your trust to an unknown entity.</p>

<p>Here are a few possible solutions - with varying degrees of complexity for the user and programmer.</p>

<ul>
    <li>Standard web-based OAuth.  Take the user to the web where they can check the URL, validate the certificate, see if they're already logged in, etc.</li>
    <li>SMS based OAuth. Type in your username (only!) to the app, receive an SMS with a one-time PIN/Password.  It's the equivalent of "Click here to verify your email address."</li>
    <li>Message based OAuth.  Type in your username (only!) to the app. Receive a Twitter DM with a one-time PIN/Password.  Retrieve the message using your trusted Twitter app or website.</li>
    <li>Use <a href="https://web.archive.org/web/20150527165523/https://get.fabric.io/digits">Twitter Digits</a> - only works if the phone number associated with the account is the phone being used.</li>
</ul>

<p>Look, all of these have a minor impact on how easy it is for a user to sign in.  Guess what - so does asking for a password.  If we wanted to make sign in nice and easy, we'd just say "Enter your username" and trust that no-one will abuse the system.</p>

<p>We must secure our users and help them to stay secure in the future.  Periscope's login model is a retrograde step for user security.</p>

<h2 id="update"><a href="https://shkspr.mobi/blog/2015/05/web-based-oauth-is-a-security-nightmare-for-apps/#update">Update!</a></h2>

<p>Here's a video showing the same problem in imgur's new Android app.</p>

<iframe title="Web Based OAuth and imgur for Android" width="620" height="349" src="https://www.youtube.com/embed/VTCFdi4zxgI?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=21073&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2015/05/web-based-oauth-is-a-security-nightmare-for-apps/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[The OAuth / App Anti-Pattern]]></title>
		<link>https://shkspr.mobi/blog/2012/04/the-oauth-app-anti-pattern/</link>
					<comments>https://shkspr.mobi/blog/2012/04/the-oauth-app-anti-pattern/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sat, 21 Apr 2012 19:48:58 +0000</pubDate>
				<category><![CDATA[mobile]]></category>
		<category><![CDATA[usability]]></category>
		<category><![CDATA[app]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[twitter]]></category>
		<guid isPermaLink="false">http://shkspr.mobi/blog/?p=5599</guid>

					<description><![CDATA[OAuth was designed to combat an anti-pattern.  Typing your username and password into a third party site is bad idea. A really bad idea. I mean, you may think it&#039;s a bad idea to give your bank details to a Nigerian prince but that&#039;s just peanuts compared to giving away your password to an untrusted site!  So, that&#039;s why we use OAuth. Rather than handing details to a random site, we authenticate…]]></description>
										<content:encoded><![CDATA[<p>OAuth was designed to combat an <a href="http://en.wikipedia.org/wiki/Anti-pattern">anti-pattern</a>.</p>

<p>Typing your username and password into a third party site is bad idea. A <em>really</em> bad idea. I mean, you may think it's a bad idea to give your bank details to a Nigerian prince but that's just peanuts compared to giving away your password to an untrusted site!</p>

<p>So, that's why we use OAuth. Rather than handing details to a random site, we authenticate against a trusted site which then redirects us back with an authentication token.</p>

<p>That's all well and good on the web, but on mobile apps it becomes a little more difficult.</p>

<p>This is the popular mobile game <a href="https://play.google.com/store/apps/details?id=com.imangi.templerun">Temple Run</a>. After dying in the game (as I frequently do!) you can Tweet your score. But, first, you need to connect with Twitter.
<img src="https://shkspr.mobi/blog/wp-content/uploads/2012/04/Temple-Run-Twitter.jpg" alt="Temple Run Twitter" title="Temple Run Twitter" width="300" height="500" class="aligncenter size-full wp-image-5601"></p>

<p>However, clicking the button, presents this screen:
<img src="https://shkspr.mobi/blog/wp-content/uploads/2012/04/Temple-Run-Twitter-OAuth.jpg" alt="Temple Run Twitter OAuth" title="Temple Run Twitter OAuth" width="300" height="500" class="aligncenter size-full wp-image-5600">
This is a pop-up within the game. What you see in the screenshot is the totality of what the user sees.</p>

<p>There are now two important questions:</p>

<ol>
    <li>How can the user tell if this is the genuine Twitter site?</li>
    <li>Why is there no indication that the site is served over HTTPS?</li>
</ol>

<p>This is a clear anti-pattern! We're teaching people to give over their usernames and passwords to sites that <em>appear</em> to be genuine - yet offer no way to validate their legitimacy.</p>

<p>We've been trying to educate people to look at the URL bar - to check that they've visited the correct site and that there's some form of SSL verification (commonly a padlock).</p>

<p>I'm not suggesting that Temple Run is doing anything other than pointing to the correct site. Just that they aren't giving the user a chance to verify the authenticity.</p>

<h2 id="how-to-solve-this-problem"><a href="https://shkspr.mobi/blog/2012/04/the-oauth-app-anti-pattern/#how-to-solve-this-problem">How To Solve This Problem</a></h2>

<p>I haven't the foggiest!  Thoughts?</p>

<p>We can't rely on the user having the Twitter app installed and firing via intent (or similar).
Due to the huge variety of phones and Operating Systems, there's no easy way (that I know of) to redirect from a website back to the app.
There needs to be a way to keep everything in-app to keep the user experience.</p>

<p>So, come on then oh great minds of the Internet, how do we fix this?</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=5599&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2012/04/the-oauth-app-anti-pattern/feed/</wfw:commentRss>
			<slash:comments>13</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[OAuth Will Murder Your Children - for one week only!]]></title>
		<link>https://shkspr.mobi/blog/2011/01/oauth-will-murder-your-children-for-one-week-only/</link>
					<comments>https://shkspr.mobi/blog/2011/01/oauth-will-murder-your-children-for-one-week-only/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Wed, 26 Jan 2011 15:39:34 +0000</pubDate>
				<category><![CDATA[usability]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[twitter]]></category>
		<guid isPermaLink="false">http://shkspr.mobi/blog/?p=3508</guid>

					<description><![CDATA[Why doesn&#039;t Twitter&#039;s OAuth let me specify the length of time a 3rd party has access to my account?  Take a look at all the crap you&#039;ve given access to your Twitter account.  Are you ever going to use that &#34;See how many of your friends like cheese&#34; app again? No.  Long time readers will know that I have  some severe usability and security concerns with Twitter&#039;s OAuth implementation.  See also my …]]></description>
										<content:encoded><![CDATA[<p>Why doesn't Twitter's OAuth let me specify the length of time a 3rd party has access to my account?  Take a look at <a href="http://twitter.com/settings/connections">all the crap you've given access to your Twitter account</a>.  Are you <em>ever</em> going to use that "See how many of your friends like cheese" app again? No.</p>

<p>Long time readers will know that I have <a href="https://shkspr.mobi/blog/2009/11/twitter-oauth-and-passwords-oh-my/"> some severe usability and security concerns with Twitter's OAuth implementation</a>.  See also <a href="http://www.theregister.co.uk/2009/11/04/oauth_dark_side/">my interview in The Register</a>.</p>

<p>Zach Holman has <a href="http://zachholman.com/2011/01/oauth_will_murder_your_children/">an entertaining and informative blog post about giving Twitter applications fine grained controls</a>.</p>

<p>Essentially, he's saying that you should be able to authorise an app for <em>just</em> posting, for example.
Here's his graphic which I've stolen.
<a href="http://zachholman.com/2011/01/oauth_will_murder_your_children/"><img src="https://shkspr.mobi/blog/wp-content/uploads/2011/01/kanye-stopped.png" alt="Fine Grained Access Controls" title="kanye-stopped" class="aligncenter size-medium wp-image-3513"></a></p>

<p>This doesn't go far enough.</p>

<p>I was taking a look at this <a href="https://web.archive.org/web/20110127083133/http://inmaps.linkedinlabs.com/">LinkedIn application which graphs your contacts</a>.</p>

<p>Take a look at their OAuth screen.</p>

<img src="https://shkspr.mobi/blog/wp-content/uploads/2011/01/Access-Duration.png" alt="Access Duration" title="Access Duration" width="521" height="418" class="aligncenter size-full wp-image-3509">

<p>At the bottom is an "Access Duration" option - giving you the option to try out the app and have it automatically revoke after a specified period of time.</p>

<p>Now, this isn't something you'd want to do for every app. But it gives you a method to limit the damage that a malicious app can do.  Remember, just because an app isn't malicious today, doesn't give you any guarantee about its future performance.</p>

<p>As it happens, the Oauth Specification 2.0 has this to say in section <a href="https://www.rfc-editor.org/rfc/rfc6749.html#section-4.2.2">4.2.2. Access Token Response</a></p>

<blockquote><p>expires_in
         OPTIONAL.  The duration in seconds of the access token
         lifetime.  For example, the value "3600" denotes that the
         access token will expire in one hour from the time the response
         was generated.</p></blockquote>

<p>If you run a service relying on OAuth, please consider giving users an Access Duration option.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=3508&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2011/01/oauth-will-murder-your-children-for-one-week-only/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[HOWTO: Twitpic and OAuth]]></title>
		<link>https://shkspr.mobi/blog/2010/05/howto-twitpic-and-oauth/</link>
					<comments>https://shkspr.mobi/blog/2010/05/howto-twitpic-and-oauth/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Mon, 31 May 2010 17:07:29 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[dabr]]></category>
		<category><![CDATA[HowTo]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[twitpic]]></category>
		<category><![CDATA[twitter]]></category>
		<guid isPermaLink="false">http://shkspr.mobi/blog/?p=2084</guid>

					<description><![CDATA[I am no longer confused!  Here is a quick tutorial in how to post images to Twitpic and Twitter when using OAuth.  I&#039;m indebted to Steve Corona of Twitpic, for his help with this.  You can see the full code on Dabr&#039;s Google Code page.  First of all, you&#039;ll need to have enabled OAuth for your Twitter client.  I use Abraham&#039;s excellent OAuth libraries for PHP.  This tutorial assumes you already…]]></description>
										<content:encoded><![CDATA[<p>I am no longer <a href="https://shkspr.mobi/blog/2010/05/twitpic-oauth-im-stuck">confused</a>!  Here is a quick tutorial in how to post images to Twitpic and Twitter when using OAuth.  I'm indebted to <a href="http://twitter.com/stevencorona">Steve Corona of Twitpic</a>, for his help with this.</p>

<p>You can see the full code on <a href="http://code.google.com/p/dabr/source/detail?r=318">Dabr's Google Code page</a>.</p>

<p>First of all, you'll need to have enabled OAuth for your Twitter client.  I use Abraham's excellent <a href="http://github.com/abraham/twitteroauth/tree/master/twitteroauth/">OAuth libraries for PHP</a>.</p>

<p>This tutorial assumes you already have OAuth working.  I'll attempt to explain what I'm doing as I go along - but the code should be pretty readable.</p>

<p>Start by reading the <a href="https://web.archive.org/web/20100522065016/http://dev.twitpic.com/docs/2/upload/">Twitpic API documentation</a>.  You will also need to register for an API key - this only takes a few seconds.</p>

<p>We start by setting CURL's headers to those required by Twitpic</p>

<pre><code class="language-php">//Has the user submitted an image and message?
if ($_POST['message'])
{
    $twitpicURL = 'http://api.twitpic.com/2/upload.json';

    //Set the initial headers
    $header = array(
                            'X-Auth-Service-Provider: https://api.twitter.com/1/account/verify_credentials.json',
                            'X-Verify-Credentials-Authorization: OAuth realm="http://api.twitter.com/"'
                        );
</code></pre>

<p>Next, we create the OAuth credentials that we need.  Essentially, we're signing a URL request. We then pass that on to Twitpic and they verify it with Twitter.  We <em>never</em> pass our OAUTH_CONSUMER_SECRET - so Twitpic can't impersonate us.</p>

<pre><code class="language-php">    //Using Abraham's OAuth library
    require_once('OAuth.php');

    // instantiating OAuth customer
    $consumer = new OAuthConsumer(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET);

    // instantiating signer
    $sha1_method = new OAuthSignatureMethod_HMAC_SHA1();

    // user's token
    list($oauth_token, $oauth_token_secret) = explode('|', $GLOBALS['user']['password']);
    $token = new OAuthConsumer($oauth_token, $oauth_token_secret);

    // Generate all the OAuth parameters needed
    $signingURL = 'https://api.twitter.com/1/account/verify_credentials.json';

    $request = OAuthRequest::from_consumer_and_token($consumer, $token, 'GET', $signingURL, array());

    $request-&gt;sign_request($sha1_method, $consumer, $token);
</code></pre>

<p>We add these generated credentials into the header.</p>

<pre><code class="language-php">    $header[1] .= ", oauth_consumer_key=\"" . $request-&gt;get_parameter('oauth_consumer_key') ."\"";
    $header[1] .= ", oauth_signature_method=\"" . $request-&gt;get_parameter('oauth_signature_method') ."\"";
    $header[1] .= ", oauth_token=\"" . $request-&gt;get_parameter('oauth_token') ."\"";
    $header[1] .= ", oauth_timestamp=\"" . $request-&gt;get_parameter('oauth_timestamp') ."\"";
    $header[1] .= ", oauth_nonce=\"" . $request-&gt;get_parameter('oauth_nonce') ."\"";
    $header[1] .= ", oauth_version=\"" . $request-&gt;get_parameter('oauth_version') ."\"";
    $header[1] .= ", oauth_signature=\"" . urlencode($request-&gt;get_parameter('oauth_signature')) ."\"";
</code></pre>

<p>Add everything into CURL</p>

<pre><code class="language-php">    //open connection
    $ch = curl_init();

    //Set paramaters
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

    //set the url, number of POST vars, POST data
    curl_setopt($ch,CURLOPT_URL,$twitpicURL);
</code></pre>

<p>The data we send to Twitpic (message text, image and key) have to go via POST.</p>

<pre><code class="language-php">    //TwitPic requires the data to be sent as POST
    $media_data = array(
                            'media' =&gt; '@'.$_FILES['media']['tmp_name'],
                          'message' =&gt; ' ' . stripslashes($_POST['message']), //A space is needed because twitpic b0rks if first char is an @
                          'key'=&gt;TWITPIC_API_KEY
                        );

    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch,CURLOPT_POSTFIELDS,$media_data);
</code></pre>

<p>All done, we now send the data to Twitpic.</p>

<pre><code class="language-php">    //execute post
    $result = curl_exec($ch);
    $response_info=curl_getinfo($ch);

    //close connection
    curl_close($ch);
</code></pre>

<p>If this has worked, Twitpic will pass back the URL of the image we posted.  We then need to post the entire message to Twitter ourselves (Twitpic can't do it for us).</p>

<pre><code class="language-php">    if ($response_info['http_code'] == 200) //Success
    {
        //Decode the response
        $json = json_decode($result);
        $id = $json-&gt;id;
        $twitpicURL = $json-&gt;url;
        $text = $json-&gt;text;
        $message = trim($text) . " " . $twitpicURL;
</code></pre>

<p>This next part is specific to Dabr - your client may post things differently.</p>

<pre><code class="language-php">        //Send the user's message to twitter
        $request = API_URL.'statuses/update.json';

        $post_data = array('source' =&gt; 'dabr', 'status' =&gt; $message);
        $status = twitter_process($request, $post_data);

        //Back to the timeline
        twitter_refresh("twitpic/confirm/$id");
    }
</code></pre>

<p>If it didn't work, Twitpic will tell us why.</p>

<pre><code class="language-php">    else
    {
        $content = "&lt;p&gt;Twitpic upload failed. No idea why!&lt;/p&gt;";
        $json = json_decode($result);
        $content .= "&lt;br /&gt;&lt;b&gt;message&lt;/b&gt; " . urlencode($_POST['message']);
        $content .= "&lt;br /&gt;&lt;b&gt;json&lt;/b&gt; " . print_r($json);
        $content .= "&lt;br /&gt;&lt;b&gt;Response&lt;/b&gt; " . print_r($response_info);
        $content .= "&lt;br /&gt;&lt;b&gt;header&lt;/b&gt; " . print_r($header);
        $content .= "&lt;br /&gt;&lt;b&gt;media_data&lt;/b&gt; " . print_r($media_data);
        $content .= "&lt;br /&gt;&lt;b&gt;URL was&lt;/b&gt; " . $twitpicURL;
        $content .= "&lt;br /&gt;&lt;b&gt;File uploaded was&lt;/b&gt; " . $_FILES['media']['tmp_name'];
    }
}
</code></pre>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=2084&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2010/05/howto-twitpic-and-oauth/feed/</wfw:commentRss>
			<slash:comments>25</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Twitpic OAuth - I'm Stuck]]></title>
		<link>https://shkspr.mobi/blog/2010/05/twitpic-oauth-im-stuck/</link>
					<comments>https://shkspr.mobi/blog/2010/05/twitpic-oauth-im-stuck/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sun, 23 May 2010 20:15:18 +0000</pubDate>
				<category><![CDATA[/etc/]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[twitpic]]></category>
		<category><![CDATA[twitter]]></category>
		<guid isPermaLink="false">http://shkspr.mobi/blog/?p=2073</guid>

					<description><![CDATA[Twitpic has implemented an OAuth API. No more having to hand out passwords to all and sundy.  Only I&#039;m too much of a dunderhead to get it working.  Perhaps it&#039;s a combination of heatstroke or this rotten head-cold, but I just can&#039;t see what I&#039;m doing wrong.  Any help much appreciated.  The easy bit.  It&#039;s easy to post the data to Twitpic  $media_data = array(     &#039;media&#039; =&#62;…]]></description>
										<content:encoded><![CDATA[<p>Twitpic has implemented an <a href="https://web.archive.org/web/20100522065016/http://dev.twitpic.com/docs/2/upload/">OAuth API</a>. No more having to hand out passwords to all and sundy.  Only I'm too much of a dunderhead to get it working.  Perhaps it's a combination of heatstroke or this rotten head-cold, but I just can't see what I'm doing wrong.  Any help much appreciated.</p>

<h2 id="the-easy-bit"><a href="https://shkspr.mobi/blog/2010/05/twitpic-oauth-im-stuck/#the-easy-bit">The easy bit.</a></h2>

<p>It's easy to post the data to Twitpic</p>

<pre><code class="language-php">$media_data = array(
    'media' =&gt; '@'.$_FILES['media']['tmp_name'],
    'message' =&gt; html_entity_decode($_POST['message']),
    'key'=&gt;'123465789132465'
);
curl_setopt($ch,CURLOPT_POSTFIELDS,$media_data);
</code></pre>

<h2 id="oauth-credentials"><a href="https://shkspr.mobi/blog/2010/05/twitpic-oauth-im-stuck/#oauth-credentials">OAuth Credentials</a></h2>

<p>Using <a href="http://twitter.com/abraham">Abrahams</a> <a href="http://github.com/abraham/twitteroauth">OAuth library for PHP</a>, it's easy to get the required OAuth data.</p>

<pre><code class="language-php">require_once('OAuth.php');
// instantiating OAuth customer
$consumer = new OAuthConsumer(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET);
// instantiating signer
$sha1_method = new OAuthSignatureMethod_HMAC_SHA1();
// user's token
list($oauth_token, $oauth_token_secret) = explode('|', $GLOBALS['user']['password']);
$token = new OAuthConsumer($oauth_token, $oauth_token_secret);

// signing URL
$fakeurl = 'https://twitter.com/account/verify_credentials.xml';
$request = OAuthRequest::from_consumer_and_token($consumer, $token, 'GET', $fakeurl, array());
$request-&gt;sign_request($sha1_method, $consumer, $token);
$OAuthurl = $request-&gt;to_url();
</code></pre>

<h2 id="the-tricky-bit"><a href="https://shkspr.mobi/blog/2010/05/twitpic-oauth-im-stuck/#the-tricky-bit">The Tricky Bit</a></h2>

<p>I'm following the header example in the <a href="https://web.archive.org/web/20100522065016/http://dev.twitpic.com/docs/2/upload/">API documentation</a>. Passing these variable to Twitpic is where I seem to go wrong.</p>

<pre><code class="language-php">$header = array(
      'X-Auth-Service-Provider: https://api.twitter.com/1/account/verify_credentials.json',
      'X-Verify-Credentials-Authorization: OAuth realm="http://api.twitter.com/"'
   );
</code></pre>

<p>I then modify the second header so it reads</p>

<pre><code class="language-php">"X-Verify-Credentials-Authorization: OAuth realm="http://api.twitter.com/",
oauth_consumer_key="aaaaaaa",
oauth_nonce="bbbbbbbbbbb",
oauth_signature="ccccccccccccc%3D",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="123456798",
oauth_token="15948715-dddddddddd",
oauth_version="1.0""
</code></pre>

<h2 id="the-error"><a href="https://shkspr.mobi/blog/2010/05/twitpic-oauth-im-stuck/#the-error">The Error</a></h2>

<p>401 "Could not authenticate you (header rejected by twitter)."</p>

<p>GAH!</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=2073&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2010/05/twitpic-oauth-im-stuck/feed/</wfw:commentRss>
			<slash:comments>13</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[The Perfect Twitter Spam Attack?]]></title>
		<link>https://shkspr.mobi/blog/2010/03/the-perfect-twitter-spam-attack/</link>
					<comments>https://shkspr.mobi/blog/2010/03/the-perfect-twitter-spam-attack/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sun, 07 Mar 2010 09:59:03 +0000</pubDate>
				<category><![CDATA[usability]]></category>
		<category><![CDATA[evil genius]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[passwords]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[twitter]]></category>
		<guid isPermaLink="false">http://shkspr.mobi/blog/?p=1796</guid>

					<description><![CDATA[This morning, when I logged on to Twitter, I saw a user who I didn&#039;t recognise tweeting away in my timeline.  I wracked my brains thinking about how they could have gotten in there before I realised it was a long-dormant friend who had changed their name and avatar.  But, in thinking about how a spammer could infiltrate one&#039;s timeline, I think I came up with a fairly bullet-proof method to spam…]]></description>
										<content:encoded><![CDATA[<p>This morning, when I logged on to Twitter, I saw a user who I didn't recognise tweeting away in my timeline.</p>

<p>I wracked my brains thinking about how they could have gotten in there before I realised it was a long-dormant friend who had changed their name and avatar.</p>

<p>But, in thinking about how a spammer could infiltrate one's timeline, I think I came up with a fairly bullet-proof method to spam Twitter users.</p>

<p>I present this as an exercise in devious thinking - and also to show how our assumptions about security can play against us. Remember, hacking and impersonation are likely to be illegal in your jurisdiction.&nbsp; This information is designed to help you understand how security weaknesses can occur.</p>

<h2 id="being-evil"><a href="https://shkspr.mobi/blog/2010/03/the-perfect-twitter-spam-attack/#being-evil">Being Evil</a></h2>

<p>Imagine you are a nasty, evil Twitter spammer.  Your own mother wouldn't spit on you if you were on fire - that's how mean you are.  Here's what you do.</p>

<ol>
    <li>Obtain a user's password.&nbsp; Admittedly, this is the hardest part of the process. You might use a dictionary attack, use the same password they use to log in to another site, or somehow steal it.</li>
    <li>Log on to Twitter.</li>
    <li>Go to "Connections" and see which services they have connected to using OAuth.&nbsp; For the purposes of this experiment, let's assume they use Example.com.</li>
    <li>Go to Example.com and OAuth yourself with Twitter using your mark's credentials.</li>
    <li>Here's where the ordinary spammer falls down.&nbsp; The ordinary spammer will start sending out messages from the mark's account.&nbsp; That's <strong>not</strong> the aim of this weakness.</li>
    <li>From the mark's account, through Example.com, make your victim follow one of your spam accounts.&nbsp; An account which exists solely to show adverts to your victim.</li>
</ol>

<p>Your victim now sees your adverts for pills, poker and porn in their timeline.&nbsp; With any luck, they'll just assume that one of their true friends is promoting your illicit wares.</p>

<h2 id="counter-attack"><a href="https://shkspr.mobi/blog/2010/03/the-perfect-twitter-spam-attack/#counter-attack">Counter Attack</a></h2>

<p>Most victims will assume that they accidentally followed your spam account - or that one of their friends has been hacked.</p>

<p>Worst case scenario, they unfollow your spam account.</p>

<p><strong><em>So you just make them follow you again!</em></strong> Remember, you are <strong>still</strong> OAuth'd to Example.com. You can make them follow as many of your spam accounts as you think you can get away with.</p>

<p>At this point, the intelligent victim will think that their account may be compromised and change their password.</p>

<p><strong><em>It doesn't matter</em>!</strong> Because you have used OAuth, password changes <em>don't affect you</em>.&nbsp; You can continue make them follow as many of your spam accounts as you think you can get away with.</p>

<p>At this point, the <em>really</em> intelligent victim will go through their OAuth connections to look for something suspicious.&nbsp; They won't find it.&nbsp; Remember steps 3 and 4?&nbsp; <strong>You are OAuth'd to a service that your victim trusts</strong>.</p>

<p>Because of the way Twitter displays OAuth information, there's no way for a victim to know when a service was last authorised.</p>

<p><img class="size-full wp-image-1798" title="Twitter OAuth Connections" src="https://shkspr.mobi/blog/wp-content/uploads/2010/03/Twitter-OAuth-Connections.png" alt="Twitter OAuth Connections" width="450" height="501"></p>

<p>There is no information other than the <em>first time</em> the OAuth was set up.&nbsp; No last accessed date, no IP addresses, nothing useful.</p>

<p>When following an account, the victim gets no notification of what has happened, when it has happened or how it has happened.&nbsp; There is no way of them knowing which of their OAuth'd connections have been compromised, nor when it happened.</p>

<p>Their only safe option is to revoke <em>every single </em>OAuth connection.&nbsp; Then reauthorise.&nbsp; A time consuming and annoying prospect.</p>

<h2 id="conclusion"><a href="https://shkspr.mobi/blog/2010/03/the-perfect-twitter-spam-attack/#conclusion">Conclusion</a></h2>

<p>I hope I've demonstrated two things.</p>

<p>Firstly, there's more to spam then just sending out messages.&nbsp; Forcing someone to read a message is just as annoying.</p>

<p>Secondly, our understanding of security and usability haven't quite caught up with the new tools which are available to us.&nbsp; OAuth is still better than giving your password to an untrusted site - but without essential usability changes, a compromised account is a lot more dangerous than the user would suspect.</p>

<p>This "attack" still relies on a victim having their original password compromised.&nbsp; That's not a trivial matter.&nbsp; But security is like sexual health - it only takes one little accident...</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=1796&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2010/03/the-perfect-twitter-spam-attack/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Twitter's new OAuth Problem]]></title>
		<link>https://shkspr.mobi/blog/2010/02/twitter-oauth-problem/</link>
					<comments>https://shkspr.mobi/blog/2010/02/twitter-oauth-problem/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Fri, 12 Feb 2010 12:10:07 +0000</pubDate>
				<category><![CDATA[mobile]]></category>
		<category><![CDATA[politics]]></category>
		<category><![CDATA[usability]]></category>
		<category><![CDATA[dabr]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[twitter]]></category>
		<guid isPermaLink="false">http://shkspr.mobi/blog/?p=1627</guid>

					<description><![CDATA[Twitter have announced that all third party site will have to use OAuth.  You will no longer be able to just type in your username and password to get access to Twitter via your favourite web client.  Usually, I would be a big fan of this move - especially if it forces password anti-pattern sites like TwitPic to implement the new, secure standard.  This means that you won&#039;t be able to log in to a …]]></description>
										<content:encoded><![CDATA[<p><a href="http://groups.google.com/group/twitter-api-announce/browse_thread/thread/c2c4963061422f28?hl=en&amp;pli=1">Twitter have announced that all third party site will have to use OAuth</a>.&nbsp; You will no longer be able to just type in your username and password to get access to Twitter via your favourite web client.</p>

<p>Usually, I would be a big fan of this move - especially if it forces <a href="http://adactio.com/journal/1357">password anti-pattern</a> sites like <a href="https://web.archive.org/web/20090804173730/https://getsatisfaction.com/twitpic/topics/when_will_twitpic_implement_oauth">TwitPic to implement the new, secure standard</a>.</p>

<p>This means that you won't be able to log in to a third party site by giving them your username and&nbsp; password.&nbsp; You will have to use OAuth to securely validate with the main Twitter site.</p>

<p>But - as ever - there's a dark side to OAuth.</p>

<h2 id="repressive-regimes"><a href="https://shkspr.mobi/blog/2010/02/twitter-oauth-problem/#repressive-regimes">Repressive Regimes</a></h2>

<p>One of the joys of Twitter is that its clients are decentralised from the main site.</p>

<p>This means that if Twitter is blocked in your country, you can use a third party client (like <a href="http://dabr.co.uk/">Dabr</a>) to access it.</p>

<p><code>Twitter User -&gt; Dabr -&gt; Twitter API -&gt; Dabr -&gt; User</code></p>

<p>If Dabr became sufficiently popular to be blocked by an oppressive regime, you can switch to any one of the thousands of Twitter web clients.</p>

<p>OAuth <strong>forces </strong>you to the main Twitter site.&nbsp; While you may visit Dabr to start with, you would be redirected to Twitter to complete OAuth.&nbsp; If Twitter is blocked, you can't connect.</p>

<h3 id="at-a-stroke-twitter-has-shut-itself-off-to-anyone-in-a-repressive-country"><a href="https://shkspr.mobi/blog/2010/02/twitter-oauth-problem/#at-a-stroke-twitter-has-shut-itself-off-to-anyone-in-a-repressive-country">At a stroke, Twitter has shut itself off to anyone in a repressive country.</a></h3>

<p><a href="http://groups.google.com/group/twitter-development-talk/browse_thread/thread/39b8b326d8b679c6">This has been picked up by some concerned users</a>.</p>

<h2 id="a-hacky-way-around-it"><a href="https://shkspr.mobi/blog/2010/02/twitter-oauth-problem/#a-hacky-way-around-it">A (Hacky) Way Around It</a></h2>

<p>There's really only one way around this problem.&nbsp; The third party web client has to act as a man-in-the-middle.&nbsp; There's a patch for Dabr - developed by <a href="https://web.archive.org/web/20100408033613/http://code.google.com/u/cnyegle/">cnyegle</a> - which will ask for a username and password, then proxy it to Twitter, get the OAuth token and tweet on behalf of the user.</p>

<p>From the user's point of view, they are still giving the (potentially untrusted) site the username and password.</p>

<h2 id="challenge-response"><a href="https://shkspr.mobi/blog/2010/02/twitter-oauth-problem/#challenge-response">Challenge Response</a></h2>

<p>This could be solved by implemented a challenge / response system.</p>

<ol>
    <li>Alice visits the Dabr website.</li>
    <li>Dabr asks Alice for her username (and <em>only</em> her username)</li>
    <li>Dabr asks Twitter for the challenge associated with Alice's username.</li>
    <li>Twitter checks that Dabr is an authorised website (i.e. has signed up for OAuth).</li>
    <li>Twitter returns the response:&nbsp; A secret phrase which Alice has previously chosen.</li>
    <li>Dabr displays this phrase to Alice.</li>
    <li>Alice knows that Twitter trusts Dabr</li>
    <li>Dabr asks Twitter for the password challenge.</li>
    <li>Twitter returns that it requires the 3rd, 5th and last character from Alice's password (the characters requested change randomly).</li>
    <li>Dabr asks Alice for <em>only</em> those characters.</li>
    <li>If Alice provides the correct characters, an OAuth token is granted to Dabr to tweet on behalf of Alice.</li>
</ol>

<p>This has the advantage of proving that Dabr is trusted (by displaying Alice's pre-defined secret phrase) and mitigating the risk that Dabr is untrusted (by only revealing part of the password).</p>

<h2 id="conclusion"><a href="https://shkspr.mobi/blog/2010/02/twitter-oauth-problem/#conclusion">Conclusion</a></h2>

<p>This is a very new area, and I've not had a chance to read through all of the proposals.&nbsp; Nevertheless, it remains a fundamental problem that, if you can't access a site, you need to delegate your trust to someone else.</p>

<p>I'm not a security expert - so I would appreciate someone pointing out the flaws in my reasoning.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=1627&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2010/02/twitter-oauth-problem/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Twitter OAuth - Mobile Failures]]></title>
		<link>https://shkspr.mobi/blog/2010/02/twitter-oauth-mobile-failures/</link>
					<comments>https://shkspr.mobi/blog/2010/02/twitter-oauth-mobile-failures/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Sun, 07 Feb 2010 15:06:26 +0000</pubDate>
				<category><![CDATA[mobile]]></category>
		<category><![CDATA[usability]]></category>
		<category><![CDATA[dabr]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[twitter]]></category>
		<guid isPermaLink="false">http://shkspr.mobi/blog/?p=1606</guid>

					<description><![CDATA[I&#039;m a big fan of OAuth - despite some claims to the contrary.  It&#039;s an excellent way of teaching people not to stick their username and password into any old site which asks for it.  Which is why I&#039;m so incredibly disappointed in Twitter&#039;s implementation of mobile OAuth.  For a service which started out operating by SMS, Twitter takes a surprisingly unenlightened view of mobile.  It&#039;s main mobile …]]></description>
										<content:encoded><![CDATA[<p>I'm a big fan of OAuth - <a href="http://www.theregister.co.uk/2009/11/04/oauth_dark_side/">despite some claims to the contrary</a>.  It's an excellent way of teaching people not to stick their username and password into any old site which asks for it.  Which is why I'm so incredibly disappointed in Twitter's implementation of mobile OAuth.</p>

<p>For a service which started out operating by SMS, Twitter takes a surprisingly unenlightened view of mobile.  It's main mobile service - <a href="http://m.twitter.com/">http://m.twitter.com/</a> - is almost completely devoid of useful features.  That's one of the main impetuses behind the development of <a href="http://dabr.co.uk/">Dabr</a>.  Their latest mobile site - <a href="http://mobile.twitter.com/">http://mobile.twitter.com/</a> - is really only suitable for the tiny minority of people who have smartphones.</p>

<p>So, understandably, many people use 3rd party sites like Dabr.  They are now faced with a dilemma - give an untrusted site their username and password or try to use OAuth on the mobile.</p>

<p>A few weeks ago came the <a href="http://groups.google.com/group/twitter-development-talk/browse_thread/thread/084f57349587b3d2/">announcement that OAuth was finally ready for mobile</a>... Was it? No.  Once again a "mobile friendly" site designed with masses of JavaScript and guaranteed not to work with the majority of phones on the market.</p>

<p>Here's how mobile OAuth looks on a variety of popular mobile phones.</p>

<h2 id="blackberry"><a href="https://shkspr.mobi/blog/2010/02/twitter-oauth-mobile-failures/#blackberry">BlackBerry</a></h2>

<p></p><div id="attachment_1607" style="width: 480px" class="wp-caption aligncenter"><img aria-describedby="caption-attachment-1607" class="size-full wp-image-1607" title="BlackBerry Twitter OAuth" src="https://shkspr.mobi/blog/wp-content/uploads/2010/02/BlackBerry-Twitter-OAuth.png" alt="BlackBerry Twitter OAuth" width="470" height="695"><p id="caption-attachment-1607" class="wp-caption-text">BlackBerry Twitter OAuth</p></div><p></p>

<p>While this looks pretty enough, it doesn't work.  The buttons <em>aren't clickable</em>.  I've tried with and without JavaScript.  No matter where I click, nothing happens.</p>

<h2 id="android"><a href="https://shkspr.mobi/blog/2010/02/twitter-oauth-mobile-failures/#android">Android</a></h2>

<p>The Android's User-Agent isn't detected by Twitter as being a mobile phone.  While it's true that the browser is very capable - the OAuth screen is a lot more usable when it's in mobile mode.</p>

<p></p><div id="attachment_1610" style="width: 330px" class="wp-caption aligncenter"><img aria-describedby="caption-attachment-1610" class="size-full wp-image-1610" title="Android Twitter OAuth" src="https://shkspr.mobi/blog/wp-content/uploads/2010/02/android2.png" alt="Android Twitter OAuth" width="320" height="480"><p id="caption-attachment-1610" class="wp-caption-text">Android Twitter OAuth</p></div><p></p>

<p>So, it works, but it doesn't look nice.</p>

<h2 id="n95"><a href="https://shkspr.mobi/blog/2010/02/twitter-oauth-mobile-failures/#n95">N95</a></h2>

<p>The N95 makes a good test phone because it's popular.  Probably more popular than the iPhone.</p>

<p></p><div id="attachment_1612" style="width: 250px" class="wp-caption aligncenter"><img aria-describedby="caption-attachment-1612" class="size-full wp-image-1612" title="N95 Twitter OAuth" src="https://shkspr.mobi/blog/wp-content/uploads/2010/02/Screenshot0106.png" alt="N95 Twitter OAuth" width="240" height="320"><p id="caption-attachment-1612" class="wp-caption-text">N95 Twitter OAuth</p></div><p></p>

<p></p><div id="attachment_1613" style="width: 250px" class="wp-caption aligncenter"><img aria-describedby="caption-attachment-1613" class="size-full wp-image-1613" title="N95 Twitter OAuth" src="https://shkspr.mobi/blog/wp-content/uploads/2010/02/Screenshot0108.png" alt="N95 Twitter OAuth" width="240" height="320"><p id="caption-attachment-1613" class="wp-caption-text">N95 Twitter OAuth</p></div><p></p>

<p>It's not pretty - but at least it works.</p>

<h2 id="others"><a href="https://shkspr.mobi/blog/2010/02/twitter-oauth-mobile-failures/#others">Others</a></h2>

<p>The Sharp GX-10 is my default test phone.  One of the first phones with a colour HTML browser.  If your site can work on this phone, it will work on any phone.  There are no screenshot capabilities for this phone - but rest assured, it does not work.</p>

<p>The three phones I've demo'd above are very popular modern phones - AKA the minority.  If they don't work well, what chance for the people using older phones?</p>

<p>Useless!  How hard can it be?  All it needs is a username field, a password field and a button.  That's just about the most basic page imaginable.  It should be child's play to make it work on mobile.</p>

<p>This was <a href="http://code.google.com/p/twitter-api/issues/detail?id=395">first raised in March 2009 on Twitter's issues list</a>. It's currently the <em>most popular</em> bug.</p>

<p>So, we're stuck in a dire situation.  Third-Party mobile sites get access to Twitter users' passwords because Twitter are unable or unwilling to develop a <em>simple</em> OAuth form.  It would be fascinating to know how many of Twitter's security breaches are down to corrupt or insecure 3rd party sites which leak passwords.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=1606&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2010/02/twitter-oauth-mobile-failures/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title><![CDATA[Twitter, OAuth and Passwords - Oh My!]]></title>
		<link>https://shkspr.mobi/blog/2009/11/twitter-oauth-and-passwords-oh-my/</link>
					<comments>https://shkspr.mobi/blog/2009/11/twitter-oauth-and-passwords-oh-my/#comments</comments>
				<dc:creator><![CDATA[@edent]]></dc:creator>
		<pubDate>Wed, 04 Nov 2009 13:04:57 +0000</pubDate>
				<category><![CDATA[usability]]></category>
		<category><![CDATA[NaBloPoMo]]></category>
		<category><![CDATA[oauth]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[twitter]]></category>
		<guid isPermaLink="false">http://shkspr.mobi/blog/?p=994</guid>

					<description><![CDATA[Twitter has a gaping security hole.  Changing your password won&#039;t stop malicious users logging in as you!  I received a rather worrying email from Twitter.  Apparently they thought my password had been compromised and needed to be reset.  Reset Your Twitter Password  After checking to see if it was valid, I went and changed my password.  Any site which relied on a cookie to post to Twitter would h…]]></description>
										<content:encoded><![CDATA[<p>Twitter has a gaping security hole.&nbsp; Changing your password <strong>won't stop malicious users logging in as you!</strong></p>

<p>I received a rather worrying email from Twitter.&nbsp; Apparently they thought my password had been compromised and needed to be reset.</p>

<p></p><div id="attachment_996" style="width: 310px" class="wp-caption aligncenter"><img aria-describedby="caption-attachment-996" class="size-medium wp-image-996" title="twitpass" src="https://shkspr.mobi/blog/wp-content/uploads/2009/11/twitpass-300x192.jpg" alt="Reset Your Twitter Password" width="300" height="192"><p id="caption-attachment-996" class="wp-caption-text">Reset Your Twitter Password</p></div><p></p>

<p>After checking to see if it was valid, I went and changed my password.&nbsp; Any site which relied on a cookie to post to Twitter would have been blocked out. Ha! Gotcha, suckers!</p>

<h2 id="the-oauth-problem"><a href="https://shkspr.mobi/blog/2009/11/twitter-oauth-and-passwords-oh-my/#the-oauth-problem">The OAuth Problem</a></h2>

<p>OAuth tokens are <strong>not</strong> revoked when the master password is changed.</p>

<p><a href="http://oauth.net/">OAuth </a>is a great idea - rather than give your username and password to any random site, you log on to Twitter and tell them that you authorise the refering site.&nbsp; The site gets an OAuth token and never gets to see your password.&nbsp; Great! Right? Not really.</p>

<p>Let's consider the following scenario.</p>

<p>Alice has a Twitter username and password.</p>

<p>Bob runs a Twitter site.</p>

<p>Alice visits Bob's site.&nbsp; Alice is security conscious and uses OAuth.</p>

<p>Eve somehow discovers Alice's password.</p>

<p>Eve also visits Bob's site and uses OAuth.</p>

<p>Alice gets suspicious about strange activity on her account and changes her password.</p>

<p>Because Bob's site uses OAuth, it <strong>does not require</strong> either Alice <em>or</em> Eve to re-enter Alice's password.</p>

<p>In this scenario, Alice has to visit <a href="http://twitter.com/account/connections">Twitter's OAuth Connections page</a> and revoke access to <em>all</em> the sites she has previously connected to.&nbsp; Alice has no way of knowing when each site was last accessed.&nbsp; She also doesn't know which site Eve is using.</p>

<p></p><div id="attachment_995" style="width: 310px" class="wp-caption aligncenter"><img aria-describedby="caption-attachment-995" class="size-medium wp-image-995" title="twitoauth" src="https://shkspr.mobi/blog/wp-content/uploads/2009/11/twitoauth-300x192.jpg" alt="Twitter's OAuth Page" width="300" height="192"><p id="caption-attachment-995" class="wp-caption-text">Twitter's OAuth Page</p></div><p></p>

<h2 id="the-problem"><a href="https://shkspr.mobi/blog/2009/11/twitter-oauth-and-passwords-oh-my/#the-problem">The Problem</a></h2>

<p>Changing a password should - in the minds of most people - mean that you need to re-enter your password even if you have previously authenticated yourself.</p>

<p>In this scenario, changing the password does not revoke access to malicious users who have previously used your credentials.</p>

<p>Twitter should revoke all OAuth tokens when a user's password is changed. It is the only way to ensure that stolen credentials cannot continue to be used after a user has changed their password.</p>

<h2 id="addendum"><a href="https://shkspr.mobi/blog/2009/11/twitter-oauth-and-passwords-oh-my/#addendum">Addendum</a></h2>

<p>As I've made clear in the comments - this <em>isn't</em> a vulnerability within OAuth per se.&nbsp; It's a usability issue which has strong security implications.</p>

<p>I spoke to Eran Hammer-Lahav (listed as <a href="http://oauth.net/advisories">OAuth's advisory contact</a>) who said:</p>

<blockquote><p>If you suspect someone stole your password, you should revoke any tokens you did not personally authorized. But there is no reason to revoke tokens just because you are changing password.</p></blockquote>

<p>While I appreciate this as the official line from those in the know, it does nothing to prevent a user who uses the same sites as you.&nbsp; For example, I can see on every tweet that you use Dabr.&nbsp; Therefore, I can safely OAuth myself as you on Dabr.&nbsp; You'll change your password, but you <em>won't</em> revoke Dabr's token because <strong>you personally authorised it</strong>.</p>

<h2 id="continuing-the-conversation"><a href="https://shkspr.mobi/blog/2009/11/twitter-oauth-and-passwords-oh-my/#continuing-the-conversation">Continuing The Conversation</a></h2>

<p>Heise Online <a href="http://www.heise.de/newsticker/meldung/Hintertuer-bei-Twitter-schliessen-850287.html">provides comentary in German</a> (<a href="http://www.h-online.com/security/news/item/Shutting-Twitter-backdoors-850717.html">English version</a>)</p>

<p>El Reg has a <a href="http://www.theregister.co.uk/2009/11/04/oauth_dark_side/">feature about Twitter and OAuth</a>.</p>

<p>There's also an <a href="http://news.ycombinator.com/item?id=921619">interesting discussion over at Hacker News</a>.</p>
<img src="https://shkspr.mobi/blog/wp-content/themes/edent-wordpress-theme/info/okgo.php?ID=994&HTTP_REFERER=RSS" alt="" width="1" height="1" loading="eager">]]></content:encoded>
					
					<wfw:commentRss>https://shkspr.mobi/blog/2009/11/twitter-oauth-and-passwords-oh-my/feed/</wfw:commentRss>
			<slash:comments>38</slash:comments>
		
		
			</item>
	</channel>
</rss>
