CINXE.COM
wikinear.com, OAuth and Fire Eagle
<!DOCTYPE html> <html lang="en-gb"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="canonical" href="https://simonwillison.net/2008/Mar/22/wikinear/"> <title>wikinear.com, OAuth and Fire Eagle</title> <script defer data-domain="simonwillison.net" src="https://plausible.io/js/plausible.js"></script> <link rel="alternate" type="application/atom+xml" title="Atom" href="/atom/everything/"> <link rel="stylesheet" type="text/css" href="/static/css/all.css"> <link rel="webmention" href="https://webmention.io/simonwillison.net/webmention"> <link rel="pingback" href="https://webmention.io/simonwillison.net/xmlrpc"> <meta name="twitter:card" content="summary"> <meta name="twitter:creator" content="@simonw"> <meta property="og:url" content="https://simonwillison.net/2008/Mar/22/wikinear/"> <meta property="og:title" content="wikinear.com, OAuth and Fire Eagle"> <meta property="og:type" content="article"> <meta property="og:description" content="I’m pleased to announce wikinear.com. It’s a simple site that does just one thing: show you a list of the five Wikipedia pages that are geographically closest to your current …"> <meta property="og:updated_time" content="1206196493"> <script async src="https://media.ethicalads.io/media/client/ethicalads.min.js"></script> </head> <body class="smallhead"> <div id="smallhead"> <div id="smallhead-inner"> <h1><a href="/">Simon Willison’s Weblog</a></h1> <a id="smallhead-about" href="/about/#subscribe">Subscribe</a> </div> </div><!-- #smallhead --> <div id="wrapper"> <div id="primary"> <div class="entry entryPage"> <div data-permalink-context="/2008/Mar/22/wikinear/"> <h2>wikinear.com, OAuth and Fire Eagle</h2> <p class="mobile-date">22nd March 2008</p> <p>I’m pleased to announce <a href="http://wikinear.com/">wikinear.com</a>. It’s a simple site that does just one thing: show you a list of the five Wikipedia pages that are geographically closest to your current location. It’s designed (or not-designed) to be used mainly from mobile phones.</p> <p>You’ll need a <a href="http://fireeagle.yahoo.net/">Fire Eagle</a> invitation code to use the site. <del>I’ve got four spare; the first four comments to ask for one can have them</del> my invites are all accounted for. If you don’t have a Fire Eagle account you’ll have to make do with this screenshot instead:</p> <p><img src="https://static.simonwillison.net/static/2008/wikinear.png" style="max-width: 100%" alt="Wikipedia pages near you. Your location: Brighton, East Sussex, England. A map shows lettered markers, and text shows a list of five Wikipedia articles - for North Laine, Brighton railway station, Cogapp, Royal Pavilion and St Bartholomew's Church, Brighton"></p> <p>The idea for the site came from living in Oxford for a year. The city is full of beautiful old historic buildings (many of them colleges), but very few of them are labelled or signposted. With wikinear.com and a GPS hooked up to Fire Eagle, I can pull out my phone and see a list of the closest points of interest, plotted on a handy map.</p> <p>Under the hood the site combines a number of interesting technologies: <a href="http://oauth.net/">OAuth</a>, <a href="http://fireeagle.yahoo.net/">Fire Eagle</a>, <a href="http://www.geonames.org/">GeoNames</a> and the new <a href="https://code.google.com/apis/maps/documentation/staticmaps/">Google Static Maps API</a>.</p> <h3>OAuth</h3> <p><a href="http://oauth.net/">OAuth</a> was originally designed to solve a problem with OpenID: in an authentication protocol based on browser redirects, how do you authenticate a desktop or command-line application? As it turned out, the solution to that problem solved a bunch of other problems that are unrelated to OpenID, so OAuth now exists as very much its own thing. In essence, it lets users delegate permission to perform actions on their behalf, without having to hand their regular authentication credentials (e.g. username and password) over to a third-party piece of software.</p> <p>If you’ve ever used a Flickr application that sends you back to Flickr to ask permission to view your private photos you’ll understand what OAuth does straight away. Before OAuth, sites had to invent their own solutions to this problem—complete with smart security measures, their own UI flow and libraries for developers wishing to access their protected APIs. OAuth provides a ready-made solution, complete with <a href="http://oauth.net/code/">tested libraries in a bunch of languages</a>.</p> <p>If you want to securely expose your user’s private data via an API, OAuth is a no-brainer. I expect to see a lot more of it over the next year.</p> <h3>Fire Eagle</h3> <p>Launched at ETech a few weeks ago, <a href="http://fireeagle.yahoo.net/">Fire Eagle</a> is a service with enormous potential. You can watch Tom Coates explain it in ten minutes in <a href="http://developer.yahoo.net/blogs/theater/archives/2008/03/fire_eagle_launches.html" title="Fire Eagle Launches">this video from the conference</a>, but the short version is that Fire Eagle acts as a <em>location broker</em>. It consists of two key OAuth-protected APIs: one for setting the geographical location of a user, and another for retrieving that location.</p> <p>This leads to a neat separation of concerns. On the one hand are the applications that attempt to figure out your location—GPS receivers, WiFi maps, mobile phones that triangulate nearby cell towers, or even sites that know where you are because you told them (Dopplr and Upcoming, for example, or the Fire Eagle site itself). On the other hand are the applications that do something useful with your location—from restaurant review sites, traffic alert services, friend finders and <a href="https://en.wikipedia.org/wiki/Alternate_reality_game">ARGs</a> down to trivial applications like wikinear.com.</p> <p>As a developer, this is really exciting. I can build location-based services without having to solve the much bigger problem of figuring out where my users are. Even better, wikinear.com becomes incrementally more useful every time someone builds a new tool for passing location information to Fire Eagle, without me having to do anything at all.</p> <p>Obviously privacy is a huge concern when dealing with this kind of data. That’s where the Fire Eagle application itself comes in: it provides a simple suite of tools for users to manage the applications that can access their location. Applications can be permitted to access different levels of accuracy or disabled entirely, and there’s a “Hide” button for disabling all applications at once.</p> <p>Disclaimer: I worked on an early prototype of Fire Eagle as my last project at Yahoo! before leaving in January 2007, but the product that has launched has changed enormously and is entirely the work of the current Fire Eagle team. wikinear.com is inspired by part of that early prototype.</p> <h3>Wikipedia and GeoNames</h3> <p>Wikipedia has a thriving community of geo-hackers, mainly focused around the <a href="https://en.wikipedia.org/wiki/Wikipedia:WikiProject_Maps">Maps</a>, <a href="https://en.wikipedia.org/wiki/Wikipedia:WikiProject_Geographical_coordinates">Geographical coordinates</a> and <a href="https://de.wikipedia.org/wiki/Wikipedia:WikiProjekt_Georeferenzierung/Wikipedia-World/en">Wikipedia-World</a> wiki projects. Many Wikipedia pages (<a href="https://en.wikipedia.org/wiki/Brighton">Brighton</a>, for example) have their co-ordinates in the top-right, added using a bewildering array of macros and markup extensions. You can browse through the huge collection of geotagged pages using <a href="https://maps.google.com/maps?q=http:%2F%2Ftools.wikimedia.de%2F~kolossos%2Fgeoworld%2FWP-world-maps.php%3Flang%3Den&ie=UTF8&om=1">this KML-powered Google Maps tool</a>—zoom in and wait a few seconds to load in more markers.</p> <p>The wonderful <a href="http://www.geonames.org/">GeoNames</a> (also used on <a href="http://djangopeople.net/">djangopeople.net</a>) includes <a href="http://www.geonames.org/wikipedia.html">an API for querying Wikipedia by location</a>, based on 610,000 articles extracted from a Wikipedia data dump. This was a huge relief when I found it, as “order by distance from X” is actually pretty tricky to do efficiently; I’ve used expanding bounding box searches in the past but I’d love to hear about more effective solutions.</p> <h3>Google Static Maps</h3> <p>A long-term criticism of the Google Maps API is that it requires JavaScript to display anything at all—once you’ve committed to using it, you’re going to have trouble implementing unobtrusive scripting (although you can <a href="http://24ways.org/2007/unobtrusively-mapping-microformats-with-jquery" title="Unobtrusively Mapping Microformats with jQuery">work around the problem</a> to some extent). Yahoo! Maps has long been better in this regard, but their <a href="http://developer.yahoo.com/maps/rest/V1/mapImage.html">map image API</a> is a bit of a pain to use—you have to do an initial call to get back the URL to an image embedded in an XML file, then extract that URL and send it to the browser.</p> <p>Launched <a href="https://googlemapsapi.blogspot.com/2008/02/google-maps-without-scripting.html" title="Google Maps Without the Scripting">last month</a>, Google’s <a href="https://code.google.com/apis/maps/documentation/staticmaps/">Static Maps API</a> is a big improvement. As with <a href="https://code.google.com/apis/chart/">Google Charts</a>, you need only construct a URL to the image to have it dynamically generated on the fly. You can also specify markers, and optionally omit the initial latitude/longitude/zoom to indicate that you want a best fit for the markers you are displaying. There’s even a flag for a “mobile optimised” image which I’m using for wikinear.com.</p> <h3>Mixing it all together</h3> <p>Excluding templates, the entire application comes in at less than 200 lines of code and took around two hours to build. The only persistence is a couple of cookies for storing Fire Eagle tokens; Django’s database layer isn’t even configured (and user locations aren’t logged anywhere, which is great from a privacy point of view). I suppose it’s a classic mashup—Fire Eagle + OAuth + Wikipedia + GeoNames + Google Static Maps = wikinear.com. Despite its simplicity (or maybe because if it), I think it’s a neat demonstration of the kind of applications Fire Eagle enables.</p> </div> <div class="entryFooter">Posted <a href="/2008/Mar/22/">22nd March 2008</a> at 2:34 pm · Follow me on <a href="https://fedi.simonwillison.net/@simon">Mastodon</a> or <a href="https://twitter.com/simonw">Twitter</a> or <a href="https://simonwillison.net/about/#subscribe">subscribe to my newsletter</a></div> </div> <div class="recent-articles"> <h2>More recent articles</h2> <ul class="bullets"> <li><a href="/2024/Nov/25/ask-questions-of-sqlite/">Ask questions of SQLite databases and CSV/JSON files in your terminal</a> - 25th November 2024</li> <li><a href="/2024/Nov/22/weeknotes/">Weeknotes: asynchronous LLMs, synchronous embeddings, and I kind of started a podcast</a> - 22nd November 2024</li> <li><a href="/2024/Nov/19/notes-from-bing-chat/">Notes from Bing Chat—Our First Encounter With Manipulative AI</a> - 19th November 2024</li> </ul> </div> </div> <!-- #primary --> <div id="secondary"> <div class="metabox"> <p class="this-is">This is <strong>wikinear.com, OAuth and Fire Eagle</strong> by Simon Willison, posted on <a href="/2008/Mar/22/">22nd March 2008</a>.</p> <a class="item-tag" href="/tags/django/" rel="tag"> django <span>566</span> </a> <a class="item-tag" href="/tags/fireeagle/" rel="tag"> fireeagle <span>15</span> </a> <a class="item-tag" href="/tags/geonames/" rel="tag"> geonames <span>7</span> </a> <a class="item-tag" href="/tags/google-maps/" rel="tag"> google-maps <span>53</span> </a> <a class="item-tag" href="/tags/oauth/" rel="tag"> oauth <span>51</span> </a> <a class="item-tag" href="/tags/wikinear/" rel="tag"> wikinear <span>6</span> </a> <a class="item-tag" href="/tags/wikipedia/" rel="tag"> wikipedia <span>41</span> </a> <p><strong>Next:</strong> <a href="/2008/May/1/orm/">jQuery style chaining with the Django ORM</a></p> <p><strong>Previous:</strong> <a href="/2008/Jan/24/upgrade/">Django People: OpenID and microformats</a></p> <div data-ea-publisher="simonwillisonnet" data-ea-type="image"></div> </div> </div> <!-- #secondary --> </div> <!-- #wrapper --> <div id="ft"> <ul> <li><a href="/about/#about-site">Colophon</a></li> <li>©</li> <li><a href="/2002/">2002</a></li> <li><a href="/2003/">2003</a></li> <li><a href="/2004/">2004</a></li> <li><a href="/2005/">2005</a></li> <li><a href="/2006/">2006</a></li> <li><a href="/2007/">2007</a></li> <li><a href="/2008/">2008</a></li> <li><a href="/2009/">2009</a></li> <li><a href="/2010/">2010</a></li> <li><a href="/2011/">2011</a></li> <li><a href="/2012/">2012</a></li> <li><a href="/2013/">2013</a></li> <li><a href="/2014/">2014</a></li> <li><a href="/2015/">2015</a></li> <li><a href="/2016/">2016</a></li> <li><a href="/2017/">2017</a></li> <li><a href="/2018/">2018</a></li> <li><a href="/2019/">2019</a></li> <li><a href="/2020/">2020</a></li> <li><a href="/2021/">2021</a></li> <li><a href="/2022/">2022</a></li> <li><a href="/2023/">2023</a></li> <li><a href="/2024/">2024</a></li> </ul> </div> <script> document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('h4[id],h5[id],h6[id]').forEach(el => { const id = el.getAttribute('id'); const permalinkContext = el.closest('[data-permalink-context]'); if (permalinkContext) { const url = permalinkContext.getAttribute('data-permalink-context'); const hashLink = document.createElement('a'); hashLink.style.borderBottom = 'none'; hashLink.style.color = '#666'; hashLink.style.fontSize = '1em'; hashLink.style.opacity = 0.8; hashLink.setAttribute('href', url + '#' + id); hashLink.innerText = '#'; el.appendChild(document.createTextNode(' ')); el.appendChild(hashLink); } }); }); </script> <script type="module"> const config = [ {"tag": "lite-youtube", "js": "/static/lite-yt-embed.js", "css": "/static/lite-yt-embed.css"} ]; for (const {tag, js, css} of config) { if (document.querySelector(tag)) { if (css) { document.head.appendChild( Object.assign(document.createElement('link'), { rel: 'stylesheet', href: css }) ); } if (js) { await import(js); } } } </script> </body> </html>