View
71
Download
4
Category
Preview:
Citation preview
GettingStartedwithOAuth2.0RyanBoyd
EditorShawnWallace
EditorMikeLoukides
Copyright©2012RyanBoyd
O’Reillybooksmaybepurchasedforeducational,business,orsalespromotionaluse.Onlineeditionsarealsoavailableformosttitles(http://my.safaribooksonline.com).Formoreinformation,contactourcorporate/institutionalsalesdepartment:(800)998-9938orcorporate@oreilly.com.NutshellHandbook,theNutshellHandbooklogo,andtheO’ReillylogoareregisteredtrademarksofO’ReillyMedia,Inc.GettingStartedwithOAuth2.0,theimageofahornedtrunkfish,andrelatedtradedressaretrademarksofO’ReillyMedia,Inc.Manyofthedesignationsusedbymanufacturersandsellerstodistinguishtheirproductsareclaimedastrademarks.Wherethosedesignationsappearinthisbook,andO’ReillyMedia,Inc.,wasawareofatrademarkclaim,thedesignationshavebeenprintedincapsorinitialcaps.Whileeveryprecautionhasbeentakeninthepreparationofthisbook,thepublisherandauthorsassumenoresponsibilityforerrorsoromissions,orfordamagesresultingfromtheuseoftheinformationcontainedherein.
O'ReillyMedia
SPECIALOFFER:UpgradethisebookwithO’ReillyClickhereformoreinformationonthisoffer!Pleasenotethatupgradeoffersarenotavailablefromsamplecontent.
ANoteRegardingSupplementalFilesSupplementalfilesandexamplesforthisbookcanbefoundathttp://examples.oreilly.com/0636920021810/.Pleaseuseastandarddesktopwebbrowsertoaccessthesefiles,astheymaynotbeaccessiblefromallereaderdevices.
Allcodefilesorexamplesreferencedinthebookwillbeavailableonline.Forphysicalbooksthatshipwithanaccompanyingdisc,wheneverpossible,we’vepostedallCD/DVDcontent.Notethatwhileweprovideasmuchofthemediacontentasweareableviafreedownload,wearesometimeslimitedbylicensingrestrictions.Pleasedirectanyquestionsorconcernstobooktech@oreilly.com.
PrefaceI’vebeenworkingwithweb-basedAPIssince1999,buildingSOAP-basedwebservicesforinternalITapplicationsandhelpingthousandsofdevelopersusingGoogle’sREST-basedAPIsforGoogleCalendar,PicasaWebAlbums,YouTube,andmore.EachoftheseAPIshasrequiredauthorizationfromuserstoactontheirbehalf.DevelopersusingtheseGoogleAPIswereinitiallyrequiredtouseproprietarytechnologieslikeClientLoginandAuthSub.IfthesesamedeveloperswantedtointegratewithAPIsprovidedbyYahoo!,theyneededtouseYahoo!’sBBAuth.TheuseoftheseproprietaryauthorizationtechnologiesmadeitchallengingtobuildapplicationsusingAPIsfrommultipleproviders.
ThedevelopmentofOAuth1.0reducedmanyoftheheadachesfordevelopersandallowedthemtouseasingleauthorizationtechnologyacrosshundredsofAPIsontheWeb.However,OAuth1.0camewithsomechallengesaswell—cryptographicsignaturesandlimiteddefinitionofhowtouseitforauthorizingapplicationsnotusingaserver-to-serverwebapplicationflow.I’mdelightedthatthestandardizationofOAuth2.0isnearlycomplete,asitprovidesanauthorizationprotocolthat’seasytousebothforthesetypesofapplicationsandforavarietyofotherusecases.
PerhapsmostexcitingistheupcomingstandardizationofOpenIDConnect—aprotocolbuiltontopofOAuth2.0toenableusingthesameidentitytologin(authenticate)tomultipleapplications.WhileI’veworkedwithhundredsofdeveloperswhohavesuccessfullybuiltearlierversionsofOpenIDauthenticationintotheirwebapplications,it’srarelybeenaverysmoothprocess.JustasOAuth2.0makesauthorizationeasierfordevelopers,OpenIDConnectdoesthesameforauthentication.
IhopethisbookgivesyouthefoundationknowledgeyouneedtoworkwithOAuth2.0andOpenIDConnectasthenext-generationauthorizationandauthenticationtechnologiesfortheWeb.
ConventionsUsedinThisBookThefollowingtypographicalconventionsareusedinthisbook:
Italic
Indicatesnewterms,URLs,emailaddresses,filenames,andfileextensions.
Constant width
Usedforprogramlistings,aswellaswithinparagraphstorefertoprogramelementssuchasvariableorfunctionnames,databases,datatypes,environmentvariables,statements,andkeywords.
Constant width bold
Showscommandsorothertextthatshouldbetypedliterallybytheuser.
Constant width italic
Showstextthatshouldbereplacedwithuser-suppliedvaluesorbyvaluesdeterminedbycontext.
TIP
Thisiconsignifiesatip,suggestion,orgeneralnote.
CAUTION
Thisiconindicatesawarningorcaution.
UsingCodeExamplesThisbookisheretohelpyougetyourjobdone.Ingeneral,youmayusethecodeinthisbookinyourprogramsanddocumentation.Youdonotneedtocontactusforpermissionunlessyou’rereproducingasignificantportionofthecode.Forexample,writingaprogramthatusesseveralchunksofcodefromthisbookdoesnotrequirepermission.SellingordistributingaCD-ROMofexamplesfromO’Reillybooksdoesrequirepermission.Answeringaquestionbycitingthisbookandquotingexamplecodedoesnotrequirepermission.Incorporatingasignificantamountofexamplecodefromthisbookintoyourproduct’sdocumentationdoesrequirepermission.
Weappreciate,butdonotrequire,attribution.Anattributionusuallyincludesthetitle,author,publisher,andISBN.Forexample:“GettingStartedwithOAuth2.0byRyanBoyd(O’Reilly).Copyright2012RyanBoyd,978-1-449-31160-5.”
Ifyoufeelyouruseofcodeexamplesfallsoutsidefairuseorthepermissiongivenabove,feelfreetocontactusatpermissions@oreilly.com.
Safari®BooksOnlineNOTE
SafariBooksOnlineisanon-demanddigitallibrarythatletsyoueasilysearchover7,500technologyandcreativereferencebooksandvideostofindtheanswersyouneedquickly.
Withasubscription,youcanreadanypageandwatchanyvideofromourlibraryonline.Readbooksonyourcellphoneandmobiledevices.Accessnewtitlesbeforetheyareavailableforprint,andgetexclusiveaccesstomanuscriptsindevelopmentandpostfeedbackfortheauthors.Copyandpastecodesamples,organizeyourfavorites,downloadchapters,bookmarkkeysections,createnotes,printoutpages,andbenefitfromtonsofothertime-savingfeatures.
O’ReillyMediahasuploadedthisbooktotheSafariBooksOnlineservice.TohavefulldigitalaccesstothisbookandothersonsimilartopicsfromO’Reillyandotherpublishers,signupforfreeathttp://my.safaribooksonline.com.
HowtoContactUsPleaseaddresscommentsandquestionsconcerningthisbooktothepublisher:
O’ReillyMedia,Inc.
1005GravensteinHighwayNorth
Sebastopol,CA95472
800-998-9938(intheUnitedStatesorCanada)
707-829-0515(internationalorlocal)
707-829-0104(fax)
Wehaveawebpageforthisbook,wherewelisterrata,examples,andanyadditionalinformation.Youcanaccessthispageat:
http://shop.oreilly.com/product/0636920021810.do
Tocommentorasktechnicalquestionsaboutthisbook,sendemailto:
bookquestions@oreilly.com
Formoreinformationaboutourbooks,courses,conferences,andnews,seeourwebsiteathttp://www.oreilly.com.
FindusonFacebook:http://facebook.com/oreilly
FollowusonTwitter:http://twitter.com/oreillymedia
WatchusonYouTube:http://www.youtube.com/oreillymedia
AcknowledgmentsI’dliketothanktheidentityandauthteamsatGoogleforprovidingyearsofguidanceandexpertise,andmostimportantlyEricSachs,MariusScurtescu,andBrenodeMedeirosfortheirreviewandfeedbackonthisbook.Ialsowouldliketothankmyfamily,friends,andcolleaguesinGoogle’sDeveloperRelationsgroupfortheirconstantsupport.
Ofcourse,withoutthefantasticworkoftheOAuthspecauthorsandworkinggroups,nobodywouldhaveachancetouseorwriteaboutOAuth.
Chapter1.IntroductionHowOAuthWasBornInthemovieFerrisBueller’sDayOff,avaletattendanttakesafullyrestored1961Ferrarioutforajoyride.Howdoyoupreventthesamethingfromhappeningtoyourbrand-newMustang?Somecarsnowcomewithspecialkeysthatallowtheownertoprovidelimitedauthorizationtovaletattendants(orkids!)andpreventactivitiessuchasopeningthetrunkanddrivingatexcessivespeeds.
OAuthwascreatedtosolvethesamecoreissueonline.
WhenGooglefirstreleasedtheGoogleCalendarAPI,itprovidedtheabilityforapplicationdeveloperstoreadandmanipulateauser’sGoogleCalendar.However,theonlywayforausertoprovidedelegatedaccesswastogivetheapplicationhisorheraccountusernameandpassword,whichtheapplicationwouldthenusewithGoogle’sproprietaryClientLoginprotocol.
ProprietaryprotocolslikeClientLoginandstandardprotocolslikeHTTPBasicauthenticationresultedinbothsmallandbigapplicationsrequestingpasswordsfromuserstogetaccesstotheirdata.Thiswasn’taffectingjustdesktopapps—applicationsallovertheWebwerepromptingforcredentials.Flickr,anonlinephoto-sharingsite,wasonesuchapplication.Originallyanindependentcompany,FlickrwasacquiredbyYahoo!afewyearsafterGoogleboughtBlogger.TheideaofYahoo!askingforGoogleuserpasswordsscaredbothfirms,leadingtothedevelopmentofnewproprietaryprotocolsthattackledthisproblemontheWeb.
Withthesenewprotocols,suchasGoogle’sAuthSub(seeFigure1-1)andYahoo!’sBBAuth,anapplicationwouldredirectuserstoanauthorizationpageontheprovider’ssiteiftheappneededaccesstouserdata.Userswouldlogintotheiraccountsandgrantaccess,andthentheapplicationwouldgetatokentouseforaccessingtheusers’data.
Figure1-1.Google’sAuthSubapprovalscreen,askingusersforpermissionfortheirGoogleCalendar
Whilethissolvedsomesecurityissues,italsocreatedcostsfordevelopers.Developersintegratingwith
multiplemajorAPIprovidershadtolearnandimplementseveralweb-basedauthorizationprotocolsintheirapplications.StartupsbuildingnewAPIswerenotcomfortableimplementingtheproprietaryauthschemes,nordevelopingtheirowncustomschemes,whichmightintroducesecurityvulnerabilities.Instead,thesestartupsandmajorAPIprovidersdecidedthattheyneededtocreateastandardprotocoltoimproveconsistencyfortheseweb-basedauthorizationflows.
WhyDevelopersShouldCareAboutOAuthWithwideadoptionofcollaborationplatformsandsocialnetworks,applicationdevelopershavetheopportunitytoconnectuserswiththeirdatawherevertheyareontheWeb.Connectinguserswiththeirdataresultsinimprovedday-to-dayefficiencybyeliminatingdatasilosandalsoallowsdeveloperstodifferentiatetheirapplicationsfromthecompetition.
OAuthprovidestheabilityfortheseapplicationstoaccessauser’sdatasecurely,withoutrequiringtheusertotakethescarystepofhandingoveranaccountpassword.
TypesoffunctionalityprovidedbyOAuth-enabledAPIsincludethefollowing:
Gettingaccesstoauser’ssocialgraph—theirFacebookfriends,peoplethey’refollowingonTwitter,ortheirGoogleContacts
Sharinginformationaboutauser’sactivitiesonyoursitebypostingtotheirFacebookwallorTwitterstream
Accessingauser’sGoogleDocsorDropboxaccounttostoredataintheironlinefilesystemofchoice
IntegratingbusinessapplicationswithoneanothertodrivesmarterdecisionsbymashingupmultipledatasourcessuchasaSalesforceCRMandTripIttravelplan
InordertoaccessorupdateprivatedataviaeachoftheseAPIs,anapplicationneedstobedelegatedaccessbytheownerofthedata.EachoftheseAPIs,andover300morearoundtheWeb(accordingtoProgrammableWebinFebruary2012),supportOAuthforgettingaccess.
HavingacommonprotocolforhandlingAPIauthorizationgreatlyimprovesthedeveloperexperiencebecauseitlessensthelearningcurverequiredtointegratewithanewAPI.Atthesametime,anauthorizationstandardcreatesmoreconfidenceinthesecurityofAPIsbecausethestandardhasbeenvettedbyalargecommunity.
WhyDon’tTheseAPIsJustUsePasswordsforAuthorization?UsernamesandpasswordsaretypicallythelowestcommondenominatorforauthenticationandauthorizationontheWeb.TheyareusedforHTTPBasicandHTTPDigestauthenticationandoncountlessloginpages.However,askingauserfortheirpasswordhasanumberofsideeffects:
Trust
Ausermaynottrustprovidingtheirpasswordtoyourapplication.
Decreasedusersensitivitytophishing
Eveniftheuseriscomfortableprovidingtheirpasswordtoyourapplication,makingtheusercomfortabledoingthisaroundtheWebcanhavenegativelong-termeffects,suchasmakingphishingscamsmoreeffective.
Expandedaccessandrisk
Whentheuserprovidestheirpasswordtoyourapplication,yougetaccesstonotonlythedatayourapplicationneeds,butallotherdataintheuser’saccount.Theapplicationhasanobligationtoitsuserstosecurelystorethesepasswordsandpreventthemfromleaking.Manydevelopersdonotwanttheriskexposureofhavingthisadditionalresponsibility.
Limitedreliability
Whenauserchangestheirpassword,yourapplicationnolongerhasaccesstotheirdata.
Revocationchallenges
Theonlywayausercanrevokeaccesstoyourapplicationisbychangingtheirpassword,whichalsorevokesaccesstoallotherapps.
Passwordsbecomerequired
WhenanAPIprovidersupportsfederatedauthenticationmechanismssuchasOpenIDorSAML(seeFederatedAuthentication),usersmaynothavepasswordsontheiraccounts.ThismakesitimpossibleforthoseuserstouseapplicationspoweredbytheAPI.
Difficultyimplementingstrongerauthentication
IfanAPIproviderrequirespasswordsforAPIauthentication,itbecomeschallengingtoimproveaccountsecuritywithtechnologieslikeCAPTCHAsormultifactorauthentication(suchasone-timepasswordtokens).
TerminologyInordertounderstandOAuth,it’simportanttofirstunderstandtherelevantterminology.We’llintroducesomekeytermsupfront,andthendiscussadditionaltermsthroughoutthebook.
AuthenticationAuthenticationistheprocessofverifyingtheidentityofauser—knowingthattheuseriswhotheyclaimtobe.
Intherealworld,whenapoliceofficerasksforyouridentification,she’sverifyingyouridentitybyensuringthatthepictureonyouridentificationmatchesyourlikeness.
OndesktopcomputersandontheWeb,authenticationisaboutknowingthattheuseratthekeyboardistheowneroftheaccount.Authenticationistypicallyperformedbyaskingauserforausernameandpassword.Theusernamerepresentstheuser’sclaimedidentity,andthesoftwareapplicationassumesthatiftheuserprovidesthecorrectpasswordthattheyareindeedthatuser.
FederatedAuthenticationAlthoughmanyapplicationshavetheirownsystemofaccounts(includingusernamesandpasswords),someapplicationsrelyonotherservicestoverifytheidentityofusers.Thisiscalledfederatedauthentication.
InacorporateITenvironment,applicationsmaytrustanActiveDirectoryserver,aLDAPserver,oraSAMLprovidertoauthenticateusers.
OntheWeb,applicationsoftentrustOpenIDproviders(suchasGoogleorYahoo!)tohandletheauthenticationofusers.Therearemanybenefitstofederationforbothapplicationdevelopersandusers.OpenIDisthemostcommonopenwebprotocolforhandlingfederatedauthentication.
AlthoughOpenIDhasbeenusedontheWebformanyyears,we’lldiscussonlyOpenIDConnect,whichisthenext-generationversionofOpenIDbasedonOAuth2.0.
AuthorizationAuthorizationistheprocessofverifyingthatauserhastherighttoperformsomeaction,suchasreadingadocumentoraccessinganemailaccount.Thistypicallyfirstrequiresvalididentificationoftheuser(authentication)inordertocheckwhethertheactualuserisauthorized.
Whenapoliceofficerpullsoveryourcarforspeeding,shefirstauthenticatesyouusingyourdriver’slicense(toverifyyouridentity)andthenchecksthelicense(expirationdate,restrictions,etc.)toensureyou’reauthorizedtodrive.
Thesameprocesshappensonline—awebapplicationfirstverifiesyouridentitybyloggingyouin,andthenitensuresthatyouaccessonlythedataandservicesyou’reallowedto,typicallybycheckinganaccesscontrollistforeachoperation.
DelegatedAuthorizationDelegatedauthorizationisgrantingaccesstoanotherpersonorapplicationtoperformactionsonyourbehalf.
Whenyoudriveyourcartoaclassyhotel,theymayoffervaletparking.Youthenauthorizethevaletattendanttodriveyourcarbyhandinghimthekeyinordertolethimperformactionsonyourbehalf.
OAuthworkssimilarly—ausergrantsaccesstoanapplicationtoperformactionsontheuser’sbehalfandtheapplicationcanonlyperformtheauthorizedactions.
RolesThereareseveralkeyactorsintheOAuthprotocolflows:
Resourceserver
Theserverhostinguser-ownedresourcesthatareprotectedbyOAuth.ThisistypicallyanAPIproviderthatholdsandprotectsdatasuchasphotos,videos,calendars,orcontacts.
Resourceowner
Typicallytheuserofanapplication,theresourceownerhastheabilitytograntaccesstotheirowndatahostedontheresourceserver.
Client
AnapplicationmakingAPIrequeststoperformactionsonprotectedresourcesonbehalfoftheresourceownerandwithitsauthorization.
Authorizationserver
Theauthorizationservergetsconsentfromtheresourceownerandissuesaccesstokenstoclientsforaccessingprotectedresourceshostedbyaresourceserver.SmallerAPIprovidersmayusethesameapplicationandURLspaceforboththeauthorizationserverandresourceserver.
TheGreatDebateoverSignaturesOAuth1.0requiredcryptographicsignaturesbesentwitheachAPIrequesttoverifytheidentityandauthorizationoftheclient.Cryptographyischallengingforthecasualdevelopertograspandalsochallengingforevenhighlyskilledengineerstomaster.Thisledtoplentyofdeveloperfrustrationand,presumably,lessadoptionofAPIsthancouldhavebeenachievedwithaneasierauthorizationprotocol.
WhenOAuth1.0wasdevelopedin2007,itwasdecidedthatcryptographicsignatureswerenecessarytosupportthesecurityofAPIs.Atthetime,manytopAPIprovidershostedtheirAPIsatvanillaHTTPendpoints,withoutSSL/TLSprotection.Overtheyears,SSL/TLSbecameamorecommonwayofprotectingAPIsandtheneedforsignaturesdecreasedintheeyesofsomemembersofthesecuritycommunity.
CombiningtheperceptionoflowAPIadoptionduetothecomplexityofcryptographyinOAuth1.0andthegreaterprevalenceofSSL/TLSsupportforAPIsledtothedevelopmentoftheOAuthWebResourceAuthorizationProfiles(WRAP)specification.OAuthWRAPisthepredecessortoOAuth2.0—iteliminatedthecomplexsignaturerequirementsandintroducedtheuseofbearertokens.
EvenasOAuth2.0nearsfinalizationinthestandardscommunity,thereremainssomestrongindividualoppositiontonotrequiringtheuseofsignatures,includingbyEranHammer-Lahav,theeditorofthespecification.EranhaswrittenablogposttitledOAuth2.0(withoutSignatures)IsBadfortheWeb,inwhichheacknowledgesthecomplexityofsignaturesforsomedevelopersbutdefendstheirvalue.HemainlypointsoutthatremovingsignaturesfromOAuth2.0makesiteasyfordeveloperstomakemistakesandaccidentallysendtheircredentialstoamaliciousAPIendpoint,whichcanthenabusethesecredentialstomakeadditionalrequestsbecausethey’renotprotectedbyasignature.Whilehearguesthatthisisn’tlikelytoday,hedoesbelieveitwillbecomemorecriticalasautomateddiscoveryisaddedforAPIandOAuthendpoints.OthersidentifycryptographicsignaturesasafeaturethatallowsforgreaterconfidenceintheoriginofAPIrequestsastherequestspassthroughmultitieredarchitectures.
Engineersoftenhavetostrikeadelicatebalancebetweensecurityandusability,andthiscaseisnodifferent.
MitigatingConcernswithBearerTokensOneoftheprimaryconcernswiththeeliminationofsignaturesisthatdeveloperswillnotproperlyverifySSL/TLScertificatechainswhenmakingrequeststotheauthorizationandresourceservers.ThisisrequiredbythespecificationandaddressedintheOAuth2.0threatmodeldocument,buttheeaseofdisablingpropercertificateandcertificateauthorityvalidationinpopularlibraries,combinedwiththedifficultyoffixingissuesassociatedwithit,hasresultedinmanydeveloperstakingshortcutsthatthreatenthesecurityoftheirapplications.
WhenimplementingOAuth2.0,callinganyAPIs,orusingalibrary,youshouldverifythatitproperlyhandlesSSL/TLScertificatechainvalidationbydoingthefollowingthings:
CheckingthatthehostnameonthecertificatereturnedbytheservermatchesthehostnameintheURLbeingaccessed
Verifyingeachcertificateinthechainproperlychainsuptoavalidandtrustedcertificateauthority(CA)
Ensuringthatthecertificateauthoritybundleonyourserverissecureandnotabletobemodifiedbypotentialattackers
SigningYourOAuth2.0RequestsTheMACAccessAuthenticationspecificationdefineshowclientscansigntheirOAuth2.0requestswhensignaturesaresupportedorrequiredbytheAPIprovider.
Author’sNote:Ifyou’rethinkingMAConlyreferstoatypeofcomputer,youcanunderstandwhysignaturesarehardformanydevelopers!Youmightwanttofindagoodbookoncryptography.
GettingthekeyInordertosignrequestsusingMACauthentication,theclientmustfirstgetaMACkey.ThiscanbeissuedbytheOAuthauthorizationserver.Inthiscase,thekeyisreturnedeachtimeanaccess_tokenisreturnedbytheauthorizationserver.ThisMACkeymustbeforuseineitherthehmac-sha-1orhmac-sha-256algorithms.Alternatively,theMACkeycanbeissuedinanout-of-bandprocess,suchaswhenthedeveloperregisterstheirapplicationwiththeAPIprovider.Regardlessofhowthekeyisissued,itmustalwaysbeissuedoverasecureSSL/TLSchannelandmustbekeptconfidential.
MakingAPIrequestsWhenconnectingtoOAuth-enabledAPIsthatrequiresignatures,eachAPIrequestmustincludeaMACsignatureintheAuthorizationheaderoftherequest.Theprocessofgeneratingthissignatureinvolvescreatinganormalizedrequeststring(nonce,HTTPmethod,requestURI,host,port,optionalbodyhash,etc.)andperformingacryptographicsignature.ItishighlyrecommendedthatdevelopersuseaprebuiltlibrarytohandleOAuthMACsigningifneeded.Ifyouneedtobuildyourownimplementation,pleaseseethespecification,asthedetailsareoutofscopeforthisbook.
DeveloperandApplicationRegistrationOAuthrequiresthatapplicationsregisterwiththeauthorizationserversothatAPIrequestsareabletobeproperlyidentified.Whiletheprotocolallowsforregistrationusingautomatedmeans,mostAPIprovidersrequiremanualregistrationviafillingoutaformontheirdeveloperwebsites.
Atthetimeofthiswriting
GooglerequiresyoutoregisteryourclientbyvisitingitsAPIsConsole,asshowninFigure1-2.
MicrosoftWindowsLiverequiresyoutoregisteryourclientusingitsapplicationmanagementsite.
FacebookrequiresyoutoregisteryourclientontheFacebookDeveloperssite.
Figure1-2.Google’sAPIsConsoleforOAuthappregistration
Asanexample,thefollowinginformationisrequiredtoregisteranOAuthclientwithGoogleviatheirAPIsConsole:
GoogleAccount
ProductName
ProductLogo(optional)
WebsiteURLusedforRedirectURIs(forwebapplicationsonly)
Afterregistrationiscomplete,thedeveloperisissuedclientcredentials:
ClientID
Specifiedasclient_idwheninteractingwiththeresourceserver
ClientSecret
Specifiedasclient_secretwhenexchanginganauthorizationcodeforanaccesstokenandrefreshingaccesstokensusingtheserver-sideWebApplicationFlow(seeFigure7-1).
WhyIsRegistrationNecessary?
Registrationenablestheapplicationdevelopertoobtainclientcredentials,whichareusedtoauthenticaterequestsmadetotheauthorizationserver.Thesecredentialsarecriticalinprotectingtheauthenticityofrequestswhenperformingoperationssuchasexchangingauthorizationcodesforaccesstokensandrefreshingaccesstokens(asdescribedinChapter2).
RegistrationalsogivestheAPIproviderinformationtoimprovetheuserexperienceduringtheauthorizationprocess.Whenpresentinganapplication’srequestfordataaccesstotheuser,theAPIproviderwilloftendisplaythenameandlogooftheapplication.
SeeFigure2-3foranexampleofhowGoogleusestheregistrationinformationontheapprovalscreen.
ClientProfiles,AccessTokens,andAuthorizationFlowsThefirstversionofOAuthwasdesignedprimarilytohandleAPIauthorizationforclassicclient-serverwebapplications.Thespecificationdidnotdefinehowtohandleauthorizationinmobileapplications,desktopapplications,JavaScriptapplications,browserextensions,orothersituations.WhileeachofthesetypesofappshavebeenwrittenusingOAuth1.0,themethodofimplementationisinconsistentandoftensuboptimal,astheprotocolwasn’tdesignedforthesecases.
OAuth2.0wasarchitectedwiththisvarietyofusecasesinmind.
ClientProfilesOAuth2.0definesseveralimportantclientprofiles:
Server-sidewebapplication
AnOAuthclientrunningonawebserver.Thewebapplicationisaccessedbyaresourceowner(user)andtheapplicationmakestheappropriateAPIcallsusingaserver-sideprogramminglanguage.TheuserhasnoaccesstotheOAuthclientsecretoranyaccesstokensissuedbytheauthorizationserver.
Client-sideapplicationrunninginawebbrowser
AnOAuthclientrunninginauser’swebbrowser,wheretheclienthasaccesstotheapplicationcodeand/orAPIrequests.TheapplicationcouldbedistributedasJavaScriptincludedinawebpage,asabrowserextension,orusingaplug-intechnologysuchasFlash.TheOAuthcredentialsarenottrustedtobekeptconfidentialfromtheresourceowner,sosomeAPIproviderswon’tissueclientsecretsforapplicationsusingthisprofile.
Nativeapplication
AnOAuthclientwhichisverysimilartotheclient-sideapplication,asthecredentialsarenottrustedtobekeptconfidential.However,sinceit’saninstalledapplication,itmaynothaveaccesstothefullcapabilitiesofawebbrowser.
AccessTokensAlthoughsignature-basedMACAccessAuthenticationwasmentionedearlier,mostOAuth2.0authorizedAPIsrequireonlybearertokenstomakeauthorizedrequests.Bearertokensareatypeofaccesstokenwherebysimplepossessionofthetokenvaluesprovidesaccesstoprotectedresources.Noadditionalinformation,suchasacryptographickey,isneededtomakeAPIcalls.
Whetheryou'rebuildingaserver-sidewebapplication,client-sidewebapplication,oranativeapplication,theendgoalofusingOAuthisthesame:you’retryingtoobtainanOAuthaccesstokenthatyourapplicationcanusetoperformAPIrequestsonbehalfofauserortheapplicationitself.
Afterobtaininganaccesstoken,thetokencanbesentalongwithyourrequestsinoneofseveralways.ThepreferredmethodofauthorizingrequestsisbysendingtheaccesstokeninaHTTPAuthorizationheader:
GET /tasks/v1/lists/@default/tasks HTTP/1.1
Host: www.googleapis.comAuthorization: Bearer ya29.AHES6ZSzX
TheAuthorizationheaderisthepreferredmechanismbecause
Theheaderisrarelyloggedbyproxyserversandwebserveraccesslogs.
Theheaderisalmostnevercached.
Theheaderdoesn’tgetstoredinthebrowsercachewhenmakingrequestsfromtheclient.
Whiletheothermechanismsaredefinedinthespecification,APIprovidersarenotrequiredtoimplementanyoftheseadditionalmethods,soyourmileagewillvary:
Queryparameter
Includingtheaccess_tokenasaURLqueryparameterisusefulfordebuggingandwhenlibrariesmakeitdifficulttomodifytheAuthorizationheader.Thismechanismisalsovaluablewhenusingtheclient-sideflowandsendingatokeninaJSONPrequest.Forexample,
https://www.googleapis.com/tasks/v1/lists/@default/tasks?callback=outputTasks&access_token=ya29.AHES6ZTh00gsAn4
Form-encodedbodyparameter
ThisisafallbackmechanismforwhenanapplicationcannotmodifytheAuthorizationheaderonrequests.ItisonlytobeusedwhenaHTTPbodywouldnormallybesentandcanthenbeaddedasanadditionalformparameterinanapplication/ x-www-form-urlencodedbody.ThismechanismisnotsupportedbytheGoogleTasksAPI.
AuthorizationFlowsEachoftheclientprofilesneedstobeaccommodatedwithanappropriateprotocolflowforobtainingauthorizationfromtheresourceownerforaccesstotheirdata.ThecoreOAuth2.0protocoldefinesfourprimary“granttypes”usedforobtainingauthorizationandalsodefinesanextensionmechanismforenablingadditionalgranttypes.
Authorizationcode
Thisgranttypeismostappropriateforserver-sidewebapplications.Aftertheresourceownerhasauthorizedaccesstotheirdata,theyareredirectedbacktothewebapplicationwithanauthorizationcodeasaqueryparameterintheURL.Thiscodemustbeexchangedforanaccesstokenbytheclientapplication.Thisexchangeisdoneserver-to-serverandrequiresboththeclient_idandclient_secret,preventingeventheresourceownerfromobtainingtheaccesstoken.Thisgranttypealsoallowsforlong-livedaccesstoanAPIbyusingrefreshtokens.
Implicitgrantforbrowser-basedclient-sideapplications
Theimplicitgrantisthemostsimplisticofallflows,andisoptimizedforclient-sidewebapplicationsrunninginabrowser.Theresourceownergrantsaccesstotheapplication,andanewaccesstokenisimmediatelymintedandpassedbacktotheapplicationusinga#hashfragmentintheURL.Theapplicationcanimmediatelyextracttheaccesstokenfromthehashfragment(usingJavaScript)andmakeAPIrequests.Thisgranttypedoesnotrequiretheintermediary“authorizationcode,”butitalso
doesn’tmakeavailablerefreshtokensforlong-livedaccess.
Resourceownerpassword-basedgrant
Thisgranttypeenablesaresourceowner’susernameandpasswordtobeexchangedforanOAuthaccesstoken.Itisusedforonlyhighly-trustedclients,suchasamobileapplicationwrittenbytheAPIprovider.Whiletheuser’spasswordisstillexposedtotheclient,itdoesnotneedtobestoredonthedevice.Aftertheinitialauthentication,onlytheOAuthtokenneedstobestored.Becausethepasswordisnotstored,theusercanrevokeaccesstotheappwithoutchangingthepassword,andthetokenisscopedtoalimitedsetofdata,sothisgranttypestillprovidesenhancedsecurityovertraditionalusername/passwordauthentication.
Clientcredentials
Theclientcredentialsgranttypeallowsanapplicationtoobtainanaccesstokenforresourcesownedbytheclientorwhenauthorizationhasbeen“previouslyarrangedwithanauthorizationserver.”ThisgranttypeisappropriateforapplicationsthatneedtoaccessAPIs,suchasstorageservicesordatabases,onbehalfofthemselvesratherthanonbehalfofaspecificuser.
Theseadditionalflowsaredefinedoutsideofthecorespec:
Deviceprofile
ThedeviceprofilewascreatedtoenableOAuthtobeusedondevicesthatdonothavebuilt-inwebbrowsersorhavelimitedinputoptions—suchasagameconsoleorelectronicphotoframe.Theusertypicallyinitiatestheflowonthedeviceandisthentoldtouseacomputertoaccessawebsiteandapproveaccessforthedevicebytypinginanauthorizationcodedisplayedinthedevice.Facebookhasagreatexampleofthisflowreferencedinitsdocumentation.
SAMLbearerassertionprofile
ThisprofileenablesexchangingSAML2.0assertionforanOAuthaccesstoken.ThisisusefulinenterpriseenvironmentsthatalreadyhaveSAMLauthorizationserverssetuptocontrolapplicationanddataaccess.
Chapter2.Server-SideWebApplicationFlowIntheWebApplicationflow(alsoknownastheAuthorizationCodeflow),theresourceownerisfirstredirectedbytheapplicationtotheOAuthauthorizationserverattheAPIprovider.Theauthorizationservercheckstoseeiftheuserhasanactivesession.Ifshedoes,theauthorizationserverpromptsherforaccesstotherequesteddata.Aftershegrantsaccess,sheisredirectedbacktothewebapplicationandanauthorizationcodeisincludedintheURLasthecodequeryparameter:
http://www.example.com/oauth_callback?code=ABC1234
Becausethecodeispassedasaqueryparameter,thewebbrowsersendsitalongtothewebserverthatisactingastheOAuthclient.Thisauthorizationcodeisthenexchangedforanaccesstokenusingaserver-to-servercallfromtheapplicationtotheauthorizationserver.ThisaccesstokenisusedbytheclienttomakeAPIcalls.
Soundconfusing?Figure2-1showstheflowstep-by-step,basedonadiagramfromthespecification.
Figure2-1.Server-sideWebApplicationflow:Step-by-step
WhenShouldtheAuthorizationCodeFlowBeUsed?TheAuthorizationCodeflowshouldbeusedwhen
Long-livedaccessisrequired.
TheOAuthclientisawebapplicationserver.
AccountabilityforAPIcallsisveryimportantandtheOAuthtokenshouldn’tbeleakedtothebrowser,
wheretheusermayhaveaccesstoit.
SecurityPropertiesTheAuthorizationCodeflowdoesnotexposetheaccesstokentotheresourceowner’sbrowser.Instead,authorizationisaccomplishedusinganintermediary“authorizationcode”thatispassedthroughthebrowser.ThiscodemustbeexchangedforanaccesstokenbeforecallscanbemadetoprotectedAPIs.Theexchangeprocessonlysucceedsifacorrectclient_secretispassedwiththerequest,ensuringconfidentialityoftheaccesstokenaslongasclientsecurityismaintained.UnlikewiththeImplicitflowdescribedinChapter3,thisconfidentialityalsoextendstotheresourceowner,meaningAPIrequestsmadewiththeaccesstokenaredirectlyattributabletotheclientanditsdevelopers.Perhapsmostimportantly—becausetheaccesstokenisneversentthroughthebrowser—thereislessriskthattheaccesstokenwillbeleakedtomaliciouscodethroughbrowserhistory,refererheaders,JavaScript,andthelike.
Althoughthereislesschanceoftheaccesstokenleakingbecauseit’snotexposedtothebrowser,manyapplicationsusingthisflowwillstorelong-livedrefreshtokensintheapplication’sdatabaseorkeystoretoenable“offline”accesstodata.Thereisadditionalriskwhenanapplicationrequireslong-livedofflineaccesstodata,asthiscreatesasinglepointofcompromiseforaccessingdatabelongingtomanyusers.Thisdoesn’texistwithotherflows,suchastheflowforclient-sidewebapplications(seeChapter3).Evenwiththisadditionalrisk,manywebsiteswillchoosetouse“offline”dataaccessbecausetheirapplicationarchitecturemakesitdifficulttointeractwiththeuser’sbrowsertoobtainnewaccesstokens.
UserExperienceLet’stakeanexampleofapayrollapplication.Thepayrollapplicationwantsaccesstoupdateamanager’stasklisttoremindthemanagertoapprovetimesheets.Byplacingtheseremindersinthemanager’stasklist,whichthemanageruseseveryday,it’smuchmorelikelythatemployeeswillgetpaidontime,reducingthenumberofangryemployeesandtime-consumingcallstotheHRdepartment.
Theuserexperienceinthemostcommoncaseisverysimple:
1. Payrollapplicationletsthemanagerknowthatit’saskingforaccesstomodifyhertasks,andredirectsherovertothetasklistapp’sOAuthauthorizationserver(seeFigure2-2).
2. TheOAuthauthorizationserverusedbythetasklistapp’sAPIpromptstheusertograntpermissionforthepayrollapplicationtoupdatehertasks(seeFigure2-3).
3. Aftertheuserhasapproved,sheisredirectedbacktothepayrollapplication,whichnowhasaccesstothetasks(seeFigure2-4).
Step-by-StepAfterregisteringyourapp(seeDeveloperandApplicationRegistration)withtheAPIproviderandobtaininganOAuthclientIDandclientsecret,it’stimetostartwritingcode!Let’sgothrougheachstepoftheflowandshowhowtheprotocolworks.We’llusePHPastheexampleprogramminglanguageandtheGoogleTasksAPIalongwithGoogle’sOAuth2.0authorizationserver.
Althoughwe’llwritethePHPcodeusingtherawOAuthprotocol,manyAPIprovidersdistributeclientlibrariesforaccessingtheirservices.TheselibrariesabstractawaysomeofthedetailsofimplementingOAuth2.0andmakeiteasierfordevelopers.YoucanfindinformationonGoogle’sPHPlibrary,whichworkswithGoogleTasks,Google+,andmanyotherGoogleAPIs,atcode.google.com.
Step1:Lettheuserknowwhatyou’redoingandrequestauthorizationSincetheOAuthflowinvolvesdirectingyouruserstothewebsiteoftheAPIprovidertoobtainauthorization,it’sabestpracticetoletthemknowinadvancewhatwillhappen.Youcandothisbydisplayingamessage,alongwithalink(the“AddtaskstoyourGoogleTasks”linkinFigure2-2).
Aftertheuserinitiatestheflow,yourapplicationwillneedtosendtheuser’sbrowsertotheOAuthauthorizationpage(asseeninFigure2-3).Thiscanbedoneeitherbysendingthemainbrowserwindowdirectlytotheauthorizationendpointorbycreatingapopup.Onthispage,theAPIproviderwillpresenttheuserwitharequesttoapprovetheapplication’sabilitytoaccesstheuser’sdata.Ofcourse,theuserneedstoalreadybesignedintotheAPIprovider,ortheywillbepromptedtoauthenticatebeforebeingaskedtograntaccesstotheirdata.
Figure2-2.Payrollapplicationlettinguserknowthey’llsoonbedirectedovertothetasklistapp’sapprovalscreen.
Figure2-3.OAuthauthorizationserveraskinguserifit’sOKtoletthepayrollapplicationaccesshisorhertasks.
Figure2-4.Payrollappthankingtheuserforaccess,andremindingthemwhatthey’llusetheaccesstoenable.
YoucanfindtheURLfortheOAuthauthorizationendpointintheAPIprovider’sdocumentation.ForGoogleTasks(andallotherGoogleAPIsusingOAuth2.0),theauthorizationendpointisat
https://accounts.google.com/o/oauth2/auth
Youwillneedtospecifyafewqueryparameterswiththislink:
client_id
Thevalueprovidedtoyouwhenyouregisteredyourapplication.
redirect_uri
Thelocationtheusershouldbereturnedtoaftertheyapproveaccessforyourapp.Forthisexample,theapplicationwillusehttps://payroll.saasyapp.com/oauth_response.php.Thevalueusedfortheredirect_uritypicallyneedstoberegisteredinadvancewiththeprovider.
scope
Thedatayourapplicationisrequestingaccessto.Thisistypicallyspecifiedasalistofspace-delimited
strings,thoughFacebookusescomma-delimitedstrings.ValidvaluesforthescopeshouldbeincludedintheAPIproviderdocumentation.ForGoogleTasks,thescopeishttps://www.googleapis.com/auth/tasks.IfanapplicationalsoneededaccesstoGoogleDocs,itwouldspecifyascopevalueofhttps://www.googleapis.com/auth/taskshttps://docs.google.com/feeds.
response_type
codefortheserver-sideWebApplicationflow,indicatingthatanauthorizationcodewillbereturnedtotheapplicationaftertheuserapprovestheauthorizationrequest.
state
Auniquevalueusedbyyourapplicationinordertopreventcross-siterequestforgery(CSRF)attacksonyourimplementation.Thevalueshouldbearandomuniquestringforthisparticularrequest,unguessableandkeptsecretintheclient(perhapsinaserver-sidesession).
Here’swhatthePHPcodemaylooklike:<?phpsession_start();
// Generate random value for use as the 'state'. Mitigates// risk of CSRF attacks when this value is verified against the// value returned from the OAuth provider with the authorization// code.$_SESSION['state'] = rand(0,999999999);
$authorizationUrlBase = 'https://accounts.google.com/o/oauth2/auth';$redirectUriPath = '/oauth2callback.php';
// For example only. A valid value for client_id needs to be obtained// for your environment from the Google APIs Console at// http://code.google.com/apis/console.$queryParams = array( 'client_id' => '240195362.apps.googleusercontent.com', 'redirect_uri' => (isset($_SERVER['HTTPS'])?'https://':'http://') . $_SERVER['HTTP_HOST'] . $redirectUriPath, 'scope' => 'https://www.googleapis.com/auth/tasks', 'response_type' => 'code', 'state' => $_SESSION['state'], 'approval_prompt' => 'force', // always request user consent 'access_type' => 'offline' // obtain a refresh token);
$goToUrl = $authorizationUrlBase . '?' . http_build_query($queryParams);
// Output a webpage directing users to the $goToUrl after// they click a "Let's Go" buttoninclude 'access_request_template.php';?>
InadditiontothestandardOAuthqueryparameters,you’llnoticewe’veincludedafewwhicharespecifictoGoogle’simplementation:
approval_prompt
Useforcetoindicatethatwewanttheuserpromptedforapprovaleachtimetheuservisitstheapplication.Youcanalsouseautotoindicatethattheuserwillonlyseetheapprovalrequestthefirsttimethisapplicationrequiresit.
access_type
Useofflinetoindicatethattheapplicationneedsaccesstouserdatawhiletheuserisnotatthekeyboard.Thisresultsinarefreshtokenbeingissuedwhentheuserexplicitlyapprovesgrantingaccesstothisapp.Ifonlineisused,norefreshtokenwillbeissued.
SomeenterpriseAPIprovidershavespecialprovisionstohandleauto-approvalofOAuth2.0grantsforanindividualuserifanITadministratoroftheuser’sorganizationhaspreviouslyapprovedaccessforanapplication.Inthisscenario,theapplicationwillredirecttheuser’sbrowsertotheauthorizationserver,buttheuserwillneverbepromptedtoapproveaccess.Instead,theuserwillbeimmediatelyredirectedbacktotheapplicationwithanauthorizationcode,asdescribedbelowinStep2:Exchangeauthorizationcodeforanaccesstoken.Salesforceprovidesthisoptionas“nouserapprovalrequired”ontheircontrolpanelpagetodefineRemoteAccessApplications.
ErrorhandlingIfallrequestparametersarevalidandtheuserapprovesthedataaccessrequest,theuserwillberedirectedbacktotheapplicationattheURLspecifiedastheredirect_uri.
However,ifoneoftherequestparametersisinvalid,anerrorconditionexists.Ifthereisanissuewiththeredirect_uri,client_id,orotherrequestinformation,theauthorizationservershouldpresentanerrormessagetotheuserandnotredirecttheuserbacktotheapplication.
Inthecasethattheuser(orauthorizationserver)deniestheaccessrequest,anerrorresponsewillbegenerated,andtheuserwillberedirectedtotheredirect_uriwithaqueryparametercallederrorindicatingthetypeoferrorasaccess_denied.Additionally,theservercanincludeanerror_descriptionmessageand/oranerror_uriindicatingtheURLofawebpagecontainingmoreinformationabouttheerror.
Whileaccess_deniedisthemostlikelyerrorresponseyourapplicationwillneedtohandle,thereareothererrortypesdefinedintheOAuth2.0specificationaswell:
invalid_request
Therequestismissingarequiredparameter,includesanunsupportedparametervalue,orisotherwisemalformed.
unauthorized_client
Theclientisnotauthorizedtorequestanauthorizationcodeusingthismethod.
unsupported_response_type
Theauthorizationserverdoesnotsupportobtaininganauthorizationcodeusingthismethod.
invalid_scope
Therequestedscopeisinvalid,unknown,ormalformed.
server_error
Theauthorizationserverencounteredanunexpectedconditionthatpreventeditfromfulfillingtherequest.
temporarily_unavailable
Theauthorizationserveriscurrentlyunabletohandletherequestbecauseofatemporaryoverloading
ormaintenanceoftheserver.
Step2:ExchangeauthorizationcodeforanaccesstokenInthecasethatnoerroroccursduringtheapprovalprocess,theauthorizationserverwillredirecttheuserbacktotheapplicationattheURLspecifiedastheredirect_uri.Inthisexample,theuserwillberedirectedbacktohttps://payroll.saasyapp.com/oauth2callback.
Whentheuserhasgrantedaccess,twoqueryparameterswillbeincludedbytheauthorizationserverintheredirectbacktothewebapplication:
code
Theauthorizationcode,indicatingthattheuserhasapprovedtherequestforaccess
state
Thevalueofthestateparameterpassedintheinitialrequesttotheauthorizationserver
ThestatevalueshouldbecomparedagainstthevaluegeneratedinStep1above.Ifthevaluesdonotmatch,it’spossibleamalicioususerisattemptingtoperformacross-siterequestforgeryattackontheapplication,sotheOAuthflowshouldnotbecontinued.
Take,forexample,https://payroll.saasyapp.com/oauth2callback?code=AB231DEF2134123kj89&state=987d43e51a262f
TheapplicationneedstoexchangethecodeforanOAuthaccesstokentomakeAPIrequests.Ifyou’reusingaclientlibraryforOAuth,thisexchangewilltypicallyhappenbehindthescenesbythelibrary.However,ifyou’renotusingalibrary,you’llneedtomakeaHTTPPOSTrequesttothetokenendpoint.Thefollowingparametersneedtobepassedintherequest:
code
Theauthorizationcodepassedtotheapplication
redirect_uri
Thelocationregisteredandusedintheinitialrequesttotheauthorizationendpoint
grant_type
Thevalueauthorization_code,indicatingthatyou’reexchanginganauthorizationcodeforanaccesstoken
ThisHTTPPOSTneedstobeauthenticatedusingtheclient_idandclient_secretobtainedduringapplicationregistration.Therearetwoprimarywaystohandletheauthenticationoftherequestdefinedinthespecification:includeaHTTPBasicAuthorizationheader(withtheclient_idastheusername,andtheclient_secretasthepassword)orincludetheclient_idandclient_secretasadditionalHTTPPOSTparameters.
AtypicalAuthorizationheaderlookslikethis:Authorization: Basic MDAwMDAwMDA0NzU1REU0MzpVRWhrTDRzTmVOOFlhbG50UHhnUjhaTWtpVU1nWWlJNg==
BecauseusingHTTPBasicaccessauthenticationwasalateradditiontotheOAuth2.0specifications,itisnotyetsupportedbymanyproviders.Instead,theHTTPPOSTparametermechanismmustbeused.The
followingadditionalPOSTparametersmustbepassedalongsidethecodeandstate:
client_id
Thevalueprovidedtoyouwhenyouregisteredyourapplication
client_secret
Theconfidentialsecretprovidedtoyouwhenyouregisteredyourapplication
Iftherequestisproperlyauthenticatedandtheotherparametersarevalid,theauthorizationserverwillissueandreturnanOAuthaccesstokeninaJSON-encodedresponse:
access_token
AtokenthatcanbeusedtoauthorizeAPIrequests
token_type
Thetypeofaccesstokenissued,often“bearer,”butthesetofpotentialvaluesisextensible
Theaccesstokenmaybetime-limited,inwhichcasesomeadditionalinformationmaybereturned:
expires_in
Theremaininglifetimeoftheaccesstoken,inseconds
refresh_token
Atokenthatcanbeusedtoacquireanewaccesstokenafterthecurrentoneexpires
TheJSON-encodedresponselookslikethis:{ "access_token" : "ya29.AHES6ZSzX", "token_type" : "Bearer", "expires_in" : 3600, "refresh_token" : "1/iQI98wWFfJNFWIzs5EDDrSiYewe3dFqt5vIV-9ibT9k"}
NOTE
BecausetheOAuthspecificationisstillindevelopment,someAPIproviderswhohaven’tcaughtupwiththelatestspecificationmayformattheirresponsesdifferently.Facebook,forinstance,returnsaform-encoded(&delimited)response.
Here’sexamplecodeforexchangingtheauthorizationcodeforanaccesstokeninPHP:<?phpsession_start();include 'http_client.inc';
$code = $_GET['code'];$state = $_GET['state'];
// Verify the 'state' value is the same random value we created// when initiating the authorization request.if ((! is_numeric($state)) || ($state != $_SESSION['state'])) { throw new Exception('Error validating state. Possible CSRF.');}
$accessTokenExchangeUrl = 'https://accounts.google.com/o/oauth2/token';$redirectUriPath = '/oauth2callback.php';
// For example only. Valid values for client_id and client_secret// need to be obtained for your environment from the Google APIs// Console at http://code.google.com/apis/console.
// Also, these values should not be hard-coded in a production application.// Instead, they should be loaded in from a configuration file or secure keystore.$accessTokenExchangeParams = array( 'client_id' => '240195362.apps.googleusercontent.com', 'client_secret' => 'hBMLD98Zi4wiqmiwmqDq', 'grant_type' => 'authorization_code', 'code' => $code, 'redirect_uri' => (isset($_SERVER['HTTPS'])?'https://':'http://') . $_SERVER['HTTP_HOST'] . $redirectUriPath);
$httpClient = new HttpClient();$responseJson = $httpClient->postData( $accessTokenExchangeUrl, $accessTokenExchangeParams);$responseArray = json_decode($responseJson, TRUE);
$accessToken = $responseArray['access_token'];$expiresIn = $responseArray['expires_in'];$refreshToken = $responseArray['refresh_token'];
$_SESSION['access_token'] = $accessToken;// Storing refresh token in the session, and using approval_prompt=force for // simplicity. Typically the fresh token would be stored in a server-side database// and associated with the user's account. This would eliminate the need for// prompting the user for approval each time.$_SESSION['refresh_token'] = $refreshToken;
header('Location: /get_data.php');?>
Nowthattheapphasanaccesstoken,theapplicationcanrespondtotheusertothankthemforgrantingauthorization,andremindthemwhatfeaturestheaccesswillenable.TheapplicationcannowaccesstheAPIsdirectlythroughthelifetimeoftheaccesstokenoruntiltheaccessisrevoked.Inthecasearefreshtokenisprovided,theapplicationcancontinuetoaccesstheAPIsofflinewithoutuserinteraction.
Theaccesstokenandtherefreshtokenshouldbekeptsecretatalltimesandtheyshouldnotbeexposedtoanyuser,includingtheresourceowner.Typicallytherefreshtokenisstoredsecurelyinaserver-sidedatabase,associatedwiththeuseraccount.Accesstokenscanalsobestoredinadatabase,buttheymayalsobecachedinaserver-sidesessiontoimproveperformance.
Whybothaccesstokensandrefreshtokens?Somedevelopersdon’tunderstandtheneedforbothshort-livedaccesstokensandlong-livedrefreshtokens.Havingbothtokentypesimprovessecurityandperformance,especiallyforlarge-scaleAPIproviderswithmanyAPIsandacentralOAuthauthorizationservice.
OAuth2.0typicallyusesbearertokens(withoutsignaturesinAPIrequests),sothecompromiseofaprotectedAPIservicecouldallowanattackertoseetheaccesstokensreceivedfromclients.AnOAuthgrantmayprovideanapplicationaccesstomultipledifferentAPIs(scopes)forauser,suchastheuser’scontactsandtheuser’scalendars.Thiscouldallowanattackeraccesstonotonlythecompromisedservice,butotherservicesaswell.Havingonlytime-limitedaccesstokensaccessibletoAPIservices(andnotlong-livedrefreshtokens)reducesthepotentialimpactofanattack.
WhenanAPIservicereceivesanaccesstokenfromaclient,itneedstoensurethatit’svalidforaccessingtherequesteddata.Ifthetokenisanopaquestring,itdeterminesthevaliditybymakinganinternalrequesttotheAPIservice’sOAuthauthorizationserviceoradatabaselookup.ThiscanintroducelatencytoAPIrequests,sosomeAPIprovidersinsteadofOAuthuseaccesstokens,whicharesignedorencryptedstrings
andareabletobeverifiedlessexpensively.
OneofthekeybenefitsofanauthorizationprotocollikeOAuthistheabilityforuserstorevokeaccesstheypreviouslygrantedtoapplications.Atlarge-scaleproviders,thisrevocationtypicallyishandledbyacentralOAuthauthorizationservicethathandlesrequestsformanyAPIs.IftheAPIservicesareindependentlyverifyingtheaccesstokensusingcryptographywithoutdatabaselookupsorcallstothecentralservice,theserviceswon’tknowwhenaccessforaclienthasbeenrevoked.Thusitisimportanttokeepthelifespanoftheaccesstokensshortsotheydonotremainvalidfortoolongaftertheclient’saccessisrevoked.
Step3:CalltheAPIThenextstepisretrievingandupdatingtheuser’stasks.ManyAPIprovidersimplementingOAuth2.0usebearertokens.ThismeansthattheapplicationcanauthorizeAPIrequestssimplybyincludingtheOAuthaccesstokenintherequests,withouttheneedforcryptographicsignatures.
ThepreferredwayofauthorizingrequestsisbysendingtheaccesstokeninaHTTPAuthorizationheader,asdiscussedinChapter1.
Here’sanexampleofusingtheAuthorizationheadermethodofmakinganauthorizedAPIcalltoretrieveauser’stasksinGoogleTasks.NotethatthiscodeisagainusingacustomHttpClientclasstoimplementtheunderlyingcallstothecurllibrary:
<?phpsession_start();require_once 'http_client.inc';
$tasksUrl = 'https://www.googleapis.com/tasks/v1/lists/@default/tasks';
// The value for $accessToken would typically be stored in a// server-side PHP session bound to the active user. The value of the// access token can be any string. Google uses values similar to:// 'ya29.AHES6ZS_2G4-VuL041L0GpFJqH0wGfGSR'.$accessToken = $_SESSION['access_token'];
// Recommended approach for an OAuth 2 authorized request is to// use a HTTP Authorization header$httpClient = new HttpClient();$headers = array( 'Authorization: Bearer ' . $accessToken);
// Alternative to using the Authorization header would be appending// the OAuth token to the URL as a query parameter// $tasksUrl .= '?access_token=' . urlencode($accessToken);
$response = $httpClient->getData($tasksUrl, $headers);$responseArray = json_decode($response, TRUE);
foreach ($responseArray["items"] as $item) { echo '<li>' . $item['title'] . "</li>\n";}?>
WhilethissamplecodespecificallydemonstratescallingtheGoogleTasksAPI,similarcodecouldbeusedtoauthorizerequestsofanyAPIsupportingrecentversionsofthedraftspecification.Simplyreplacethevaluesof$tasksUrland$accessToken.
Errorhandling
WhenmakingAPIcallsusingtheOAuth2.0accesstoken,youmayencountererrorsiftheaccesstokenisnolongervalidbecausethetokenexpiredorwasrevoked.Inthiscase,youshouldgetaHTTP4xxerror.DependingontheindividualAPI,thedetailederrordescriptionwillbecommunicateddifferently.
Inadditiontothe4xxerrorcode,thelatestversionoftheOAuthbearertokenspecificationalsorequiresthattheHTTPWWW-AuthenticateresponseheaderbeincludedwhencredentialsarenotincludedintherequestortheaccesstokenprovideddoesnotenableaccesstotherequestedAPIresource.Thisheadermayincludeadditionaldetailsontheerrorencountered.
Here’sanexampleresponsefromthespecification,indicatingthatanexpiredOAuthaccesstokenwaspassedtotheapp:
HTTP/1.1 401 UnauthorizedWWW-Authenticate: Bearer realm="example", error="invalid_token", error_description="The access token expired"
Validerrorcodesinclude:invalid_request,invalid_token,andinsufficient_scope.
BecausetheuseoftheWWW-Authenticateheaderwasalateadditiontothespec,itmaynotbeimplementedbyallofyourfavoriteAPIproviders.
WhenFacebookencountersanerrorwiththetoken,itreturnsaHTTP400statuscodeandincludesthefollowingJSONobjectinthebodyoftheresponse:
{ "error": { "type": "OAuthException", "message": "Error validating access token." }}
Here’sanexampleresponseresultingfromtheuseofanexpiredaccesstokenwithoneofGoogle’snewerAPIs:
{ "error": { "errors": [ { "domain": "global", "reason": "authError", "message": "Invalid Credentials", "locationType": "header", "location": "Authorization" } ], "code": 401, "message": "Invalid Credentials" }}
Step4a:RefreshtheaccesstokenWhenanauthorizationcodeisexchangedforanaccesstoken,manyAPIproviderswillissueshort-livedaccesstokenseveniftheysupportlong-lived“offline”accesstotheirAPIs.Althoughtheseaccesstokenshavealimitedlifespan,twoadditionalparametersmaybeincludedintheresponsetoenablelong-livedaccess:expires_inandrefresh_token.
Ifincludedintheresponse,expires_inindicatestheremaininglifetimeoftheaccess_token,specified
inseconds.Whentheaccesstokenexpires,therefresh_tokenparametercanbeusedtoobtainanewaccesstoken.
Iftryingtooptimizeforlatencyinyourapplication,it’sbesttostoretheaccesstokenalongwiththetimewhentheaccesstokenexpires.WhenmakinganAPIcall,firstchecktoseeifthecurrenttimeisgreaterthantheexpirationtime.Ifso,refreshtheaccesstokenfirst,insteadofwaitingfortheAPIservertorejectyourrequestbecauseofaninvalidaccesstoken.ThiswillresultinreducedlatencybecauseoffewerHTTPrequestsbeingmadewhenthetokenexpires.
RefreshingtheaccesstokenisaccomplishedbymakingaHTTPPOSTtothetokenendpoint,specifyingthegrant_typeasrefresh_tokenandincludingtherefresh_token.Therequestmustalsobeauthenticated.
Here’sanexampleinPHP:<?phpinclude 'http_client.inc';
function getNewAccessToken($refreshToken) { $refreshTokenUrl = 'https://accounts.google.com/o/oauth2/token';
// For example only. Valid values for client_id and client_secret // need to be obtained for your environment from the Google APIs // Console at http://code.google.com/apis/console. $refreshTokenParams = array( 'client_id' => '240195362.apps.googleusercontent.com', 'client_secret' => 'hBMLD98Zi4wiqmiwmqDq', 'grant_type' => 'refresh_token', 'refresh_token' => $refreshToken );
$httpClient = new HttpClient(); $responseJson = $httpClient->postData( $refreshTokenUrl, $refreshTokenParams); $responseArray = json_decode($responseJson, TRUE); return $responseArray;}
$responseArray = getNewAccessToken('adbadsfa12345');$accessToken = $responseArray['access_token'];$refreshToken = $responseArray['refresh_token'];$expiresIn = $responseArray['expires_in'];?>
Thisexampleauthenticatestherequestbyincludingtheclient_idandclient_secretasHTTPPOSTparameters.SomeOAuthprovidersmayalsosupportauthenticatingtherequestusingtheHTTPBasicaccessauthenticationmethoddescribedinStep2.
Whenrequestinganewaccesstoken,anewrefreshtokenmaybeissuedaswell.Inthiscase,storethenewrefreshtokenanddiscardthepreviousone.
Step4b:ObtaininganewaccesstokenRegardlessofwhetherAPIcallsarebeingmadedirectfromauser’sbrowserorserver-to-server,someapplicationsonlyneedaccesstoauser’sdatawhiletheuseris“atthekeyboard.”Inthiscase,theapplicationmaybeabletorequest“online”accessthatresultsinnorefreshtokenbeingissuedandtheaccesstokenhavingalimitedlifespan.Inthiscase,obtaininganewaccesstokenisdonebysendingthe
userthroughtheauthorizationflow,startingatStep1again.SomeAPIproviderswillnotreprompttheuserforaccessiftheapplicationhaspreviouslybeengrantedaccesstothesamesetofdatabytheuserandwillinsteadredirectimmediatelybacktotheapplicationwithanauthorizationcode.
Herearesomespecificimplementations:
Googledefaultsto“online”accessanddoesnothandoutrefreshtokensunlessexplicitlyrequestedbypassingaccess_type=offlinetotheauthorizationendpointatthetimeanauthorizationcodeisrequested(seeStep1).Inthiscase,theuseriswarnedthattheyaregrantingpermissionfortheapplicationto“PerformtheseoperationswhenI’mnotusingtheapplication.”Ifanapplicationwithonly“online”accessneedsanewauthorizationcode,itisautomaticallyissuedtotheclientwithoutuserinteraction,andthenexchangedbytheapplicationinaserver-to-servercall(seeStep2).
Facebookdefaultsto“online”access:itissuesaccesstokenswithlimitedlifespananddoesnotissuerefreshtokens.Ifanapplicationneedsofflineaccess,itcanrequestoffline_accessbyspecifyingthispermissionasoneofthevaluesinthescopestring.Thiswillresultinanaccesstokenbeingissuedwithaninfiniteexpirationtime,thoughthetokenwillstillbesubjecttopotentialrevocationbytheuser.
HowCanAccessBeRevoked?Differentauthorizationservershavedifferentpoliciesastowhenaccesstokensarerevoked.Mosttypicallyenabletheusertoexplicitlyrevokeaccessthroughanaccountmanagementinterface,thoughtheseinterfacescanbedifficultforuserstofind.Additionally,someAPIproviders(suchasFacebook)revokeoutstandingaccesstokenswhenauserchangestheirpassword.
Applicationsarenotusuallyinformedwhenauserrevokesaccess,andthespecificationdoesnotdefineanywaytoimplementanotification—theappwillsimplyseeanerrorthenexttimeitattemptstouseanaccesstokenorrefreshthetokenstoredforthatuser.
Facebook,however,doeshaveadefinable“DeauthorizecallbackURL”whichperformsaHTTPPOSTtoyourapplicationwhenauserrevokesaccessinthestyleofaWebHook.MoreinformationisavailableinFacebook’sdeveloperdocumentation.
Whileuserscanrevoketheiraccessmanually,someOAuth2.0authorizationserversalsoallowtokenstoberevokedprogrammatically.Thisenablesanapplicationtocleanupafteritselfandremoveaccessitnolongerneedsif,forinstance,theuseruninstallstheapp.
ProgrammaticrevocationisdefinedinadraftextensiontotheOAuth2.0specificationandisimplementedbypopularOAuthproviderssuchasSalesforceandGoogle.Salesforceallowsforrevocationofbothrefreshtokensandaccesstokens,whileGoogleonlyenablesrevocationofrefreshtokens.Here’sanexamplerevocationrequest:
curl "https://accounts.google.com/o/oauth2/revoke?token=ya29.AHES6ZSzF"
TheextensionalsodefinesaJSONP“callback”queryparameterthatOAuthproviderscanoptionallysupport.BothSalesforceandGooglesupportthisparameter.
A200responsecodeindicatessuccessfulrevocation.
Chapter3.Client-SideWebApplicationsFlowTheImplicitGrantflowforbrowser-basedclient-sidewebapplicationsisverysimple.Inthisflow,anaccesstokenisimmediatelyreturnedtotheapplicationafterausergrantstherequestedauthorization.Anintermediateauthorizationcodeisnotrequiredasitisintheserver-sideWebApplicationflow(seeChapter2).
Figure3-1showsastep-by-stepflowdiagram,basedonadiagramfromthespecification.
Figure3-1.Client-SideWebApplicationsflow:Step-by-step
WhenShouldtheImplicitGrantFlowBeUsed?TheImplicitGrantflowshouldbeusedwhen
Onlytemporaryaccesstodataisrequired.
TheuserisregularlyloggedintotheAPIprovider.
TheOAuthclientisrunninginthebrowser(usingJavaScript,Flash,etc.).
Thebrowserisstronglytrustedandthereislimitedconcernthattheaccesstokenwillleaktountrustedusersorapplications.
LimitationsoftheImplicitGrantFlowTheImplicitGrantflowdoesnotaccommodaterefreshtokens.IftheAuthorizationserverexpiresaccesstokensregularly,yourapplicationwillneedtorunthroughtheauthorizationflowwheneveritneedsaccess.
SomeAPIproviders,suchasGoogle,willnotreprompttheuserforaccessiftheuserremainsloggedinandhasapprovedtherequiredscopespreviously.Theapplicationcandothis“refresh”processinthebackgroundasaniframewithoutanyimpactontheuserexperience.
SecurityPropertiesIntheImplicitGrantflow,theapplicationdoesnotstorelong-livedrefreshtokensonaserver,limitingtheexposureiftheserveriscompromised.ItalsorequiresthattheuserbeauthenticatedtotheAPIprovider’sauthorizationserverinorderto“refresh”accesstokensontheclient,ensuringthataleakedaccesstoken’svalueistime-limited,dependingontheOAuthimplementation.
Becausetheaccesstokenissenttotheuser’swebbrowser,thisflowofferslessaccountabilitythantheAuthorizationCodeflow.APIcallsthatappeartohaveoriginatedfromathird-partyappmayhaveinfactbeenmadedirectlybytheresourceownerthemselves.
UserExperienceAJavaScript-basedContactspickerforselectinguserstoinvitetoaPhotoViewerapplicationisagreatexampleusecasefortheImplicitGrantflow.Itisavaluableactivityforboththeuserandtheapplicationdeveloper,itdoesn’thappenregularly,andtheuserisalwaysresponsibleforchoosingwhichuserstoinvitefromhisorhercontacts.
TheuserexperienceisidenticaltotheServer-SideWebApplicationflowdescribedinChapter2:
1. PhotoViewerapplicationletstheuserknowthatitneedsaccesstoherContacts.
2. TheOAuthauthorizationserverusedbytheContactapp’sAPIpromptstheusertograntpermissionforthePhotoViewerapplicationtoreadhercontacts.
3. Aftertheuserhasapproved,sheisredirectedbacktothePhotoViewerapplication,whichnowhasaccesstohercontacts.
Step-by-StepLikeinthecaseoftheflowforServer-sideWebApplicationsdescribedinChapter2,you’llfirstneedtoregisteryourapplicationwiththeAPIprovider(seeDeveloperandApplicationRegistration).
Afterregistrationiscomplete,it’stimetowritesomecode!We’llusesimpleHTMLandJavaScriptforthisexample.
Step1:Lettheuserknowwhatyou’redoingandrequestauthorizationThisstepisverysimilartotheAuthorizationCodeflow.Sincerequestingdataaccessrequiresredirectingyouruserstotheauthorizationserver,it’sabestpracticetoletthemknowinadvancewhatwillhappen.Youcandothisbydisplayingamessage,alongwithalinkthatdirectstheusertotheOAuthauthorizationendpoint.
YoucanfindtheURLfortheOAuthauthorizationendpointintheAPIprovider’sdocumentation.ForGoogleTasks(andallotherGoogleAPIsusingOAuth2.0),theauthorizationendpointisat
https://accounts.google.com/o/oauth2/auth
Youwillneedtospecifyafewqueryparameterswiththislink:
client_id
Thevalueprovidedtoyouwhenyouregisteredyourapplication.
redirect_uri
Thelocationtheusershouldbereturnedtoaftertheyapproveaccessforyourapp.Forthisexample,theapplicationwillusehttps://photoviewer.saasyapp.com/oauth_response.html.
scope
Thedatayourapplicationisrequestingaccessto.Thisisspecifiedasalistofspace-delimitedstrings.ValidvaluesforthescopeshouldbeincludedintheAPIproviderdocumentation.ForGoogleContacts,thescopeishttps://www.google.com/m8/feeds/.
response_type
Thetokenfortheclient-sideWebApplicationflow,indicatingthatanaccesstokenwillbereturnedtotheapplicationaftertheuserapprovestheauthorizationrequest.
Thecompletecodeforhandlingthisflow(inindex.html)islong,solet’sexploreitinsnippets.
ThisinitialsnippetopensapopupwindowtotheauthorizationURL.Theclient_id,scope,andresponse_typearesettotheappropriatevalues.Apseudo-randomstatevalueisgeneratedinordertomitigatetheriskofCSRFattacks.We’vealsosettheredirect_uritoapagethatcontainsJavaScriptforparsingtheaccesstokenfromtheURLandpassingitbacktotheparentwindow:
<script type="text/javascript"> var clientId = '1032068783357.apps.googleusercontent.com'; var authorizationUrlBase = 'https://accounts.google.com/o/oauth2/auth'; var redirectUri = 'http://photoviewer.saasyapp.com/pv/oauth2callback.html'; var scope = 'https://www.google.com/m8/feeds/';
var state;
function startOauth() { // generate a pseudo-random number for state var rand = Math.random(); var dateTime = new Date().getTime(); state = rand * dateTime; var url = authorizationUrlBase; url += '?response_type=token' + '&redirect_uri=' + encodeURIComponent(redirectUri) + '&client_id=' + encodeURIComponent(clientId) + '&scope=' + encodeURIComponent(scope) + '&state=' + encodeURIComponent(state); var w = window.open(url, '_blank', 'width=500,height=400'); }</script>
ErrorhandlingSeethedescriptionforerrorhandlinginStep1oftheServer-sideWebApplicationsflow(Chapter2).Thesameerrorhandlingprocessappliestothisflow.
Step2:ParsingtheaccesstokenfromtheURLAftertheuserapprovesaccess,thepopupwindowisredirectedbacktothespecifiedredirect_uriandanaccess_tokenisincludedinthe#hashfragment.Here’sanexampleURLforthisapplication:
http://photoviewer.saasyapp.com/pv/oauth2callback.html#access_token=ya29.AHES6ZSzX&token_type=Bearer&expires_in=3600
JavaScriptdoesn’ttraditionallytreatelementsofthehashfragmentasname/valuepairs,soweneedtoparseoutthevalueoftheaccess_tokenandotherelementsoftheOAuthresponse:
var oauthParams = {};
// parse the query string// from http://oauthssodemo.appspot.com/step/2var params = {}, queryString = location.hash.substring(1), regex = /([^&=]+)=([^&]*)/g, m;while (m = regex.exec(queryString)) { oauthParams[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);}
...
Next,weneedtopasstheaccesstokentotheparentwindow:window.opener.setOauthParams(oauthParams);
Thispassestheaccesstokenbacktothemainbrowserwindow.ToprotectagainstCSRFattacks,thesetOAuthParamsmethodshouldcheckthatoauthParams['state']matchestheglobalstatevariablesetinstartOAuthabove.
Thismechanismofcommunicatingwiththeparentwindowworksinmodernbrowsers.However,thesame-originpolicyisenforced,sothepopupwindowneedstomatchthehost/port/protocolofthemainwindow.
GooglehasimplementedamoreelegantwayforOAuth2.0popupwindowstocommunicateusingtheHTML5window.postMessagefeature.Thisisnotwidelydeployedyet,butyoucanseeasampleimplementationonGoogleProjectHosting.
Step3:CalltheAPI
WeusejQueryforcallingtheAPItomakeitabiteasier.Instead,youcouldcreatea<script>elementpointingtotheJSONPURLfortheContactsAPIanddynamicallyappendittothe<head>elementofyourwebpage.
ThecallApi()functionbelowwillretrievetheuser’scontactsasJSONandcallthesetResponsefunctionwiththedata:
function callApi() { var contactsUrl = 'https://www.google.com/m8/feeds/contacts/default/full?v=3.0&alt=json-in-script'; document.getElementById('access_request').style.display = 'none'; var oauthParams = this.getOAuthParams(); contactsUrl += "&access_token=" + encodeURIComponent(oauthParams['access_token']); $.ajax({ 'url': contactsUrl, 'dataType': 'jsonp', 'success': function(data) { setResponse(data); } });}
Noticethatweappendedtheaccess_tokentotheURLinsteadofusingthepreferredAuthorizationheadermechanism.ThisisbecausejQuerydoesnotallowmanuallysettingtheAuthorizationheaderusedontheserequests.
Step4:RefreshingtheaccesstokenUnlikewiththeAuthorizationCodeflowforserver-sidewebapplications,thereisnospecialprotocolforrefreshingtokenswhenusingtheImplicitGrantflow.Yourapplicationwillsimplyneedtorequestanewaccesstokenusingthesameprocessasyouusedtofetchtheinitialtoken(Steps1to3above).
Someproviders,likeGoogle,willnotpresentanauthorizationrequesttotheuseriftheyhavepreviouslyapprovedaccessforyourapplication.However,theuserwillneedtobeloggedintotheirGoogleaccountforanewtokentobeissuedwithouttheauthorizationserverpromptingtheuserfortheirGoogleaccountpassword.
Althoughnotstandardizedyet,supportforan“immediate”modealsoexistsinsomeOAuth2.0providers.Thisallowsthisrefreshprocesstooccurinahiddeniframe,enablinganewaccesstokentobetransparentlysentbacktotheapplicationwithouttheriskofpromptingtheuser.Iftheuserwouldotherwisebepromptedtoauthenticateorgrantaccess,immediatemodewillinsteadcausethewindowtoberedirectedbacktotheappwithanerrormessageindicatingthefailure.Thisallowstheapptogracefullyprompttheuserasneededforrenewedauthorization.
FortheGoogleandSalesforceOAuthauthorizationendpoints,youcanprovideanadditionalqueryparametervalueimmediate=truetoenableimmediatemode.
HowCanAccessBeRevoked?SeethedescriptionfortokenrevocationintheServer-sideWebApplicationsflow(Chapter2)section.Thesametokenrevocationprocessappliestothisflow.
Chapter4.ResourceOwnerPasswordFlowTheResourceOwnerPasswordCredentialsflowallowsexchangingtheusernameandpasswordofauserforanaccesstokenand,optionally,arefreshtoken.ThisflowhassignificantlydifferentsecuritypropertiesthantheotherOAuthflows.Theprimarydifferenceisthattheuser’spasswordisaccessibletotheapplication.Thisrequiresstrongtrustoftheapplicationbytheuser.
Figure4-1showsastep-by-stepflowdiagram,basedonadiagramfromthespecification.
Figure4-1.ResourceOwnerPasswordflow:Step-by-step
WhenShouldtheResourceOwnerPasswordFlowBeUsed?Becausetheresourceowner’spasswordisexposedtotheapplication,thisflowshouldbeusedsparingly.Itisrecommendedonlyforfirst-party“official”applicationsreleasedbytheAPIprovider,andnotopeneduptowiderthird-partydevelopercommunities.
Ifauserisaskedtotypetheirpasswordinto“official”applications,theymaybecomeaccustomedtodoing
soandbecomevulnerabletophishingattemptsbyotherapps.Inordertomitigatethisconcern,developersandITadministratorsshouldclearlyeducatetheirusershowtheyshoulddeterminewhichappsare“official”andwhicharenot.
SecurityPropertiesAlthoughtheapplicationhasaccesstotheresourceowner’spassword,therearestillsomesecuritybenefitstousingthisflowversusauthenticatingAPIcallswithausernameandpassword(viaHTTPBasicaccessauthenticationorsimilar).WithBasicauthentication,anapplicationneedstohavecontinuousaccesstotheuser’spasswordinordertomakeAPIcalls.Italsorequirestheuserchangetheirpasswordandreenterthenewpasswordinallapplicationswhichrequireit,shouldtheusernolongerwantanapplicationtohaveaccesstotheirdata.
However,iftheOAuthResourceOwnerPasswordflowisused,theapplicationonlyneedsaccesstotheuser’scredentialsonce:onfirstusewhenthecredentialsareexchangedforanaccesstoken.Thismeansthere’snorequirementfortheapptostorethesecredentialswithintheapplicationoronthedevice,andrevokingaccessiseasyaswell.
UserExperienceTheuserexperienceforthisflowisidenticaltotypicalpassword-basedaccessrequests.Theapplicationaskstheuserfortheirusernameandpasswordandtheuserprovidestheinformation.Theapplicationthenmakeseitheraserver-sideorclient-siderequesttotheAPIprovider’sauthorizationserver,withoutanyuser-facinginterfacechanges.
IftheAPIproviderdoesnotissuearefresh_tokenandtheissuedaccess_tokenisshort-lived,theapplicationwilllikelystoretheusernameandpasswordforfutureauthenticationattempts.Unfortunately,thisdefeatssomeofthebenefitofthisflow.
Step-by-StepTodemonstratethisflow,we’lluseanexamplebuiltontopofSalesforce’sREST-basedAPIs.OurexamplewillretrieveandoutputallcontactsaccessibletotheresourceownerintheSalesforceCRMsystem.
We’llassumetheexampleapplicationisanativemobileapplicationwrittenbyAcmeCorporationanddistributedtoitsemployeesthroughacorporateapplicationdirectory.Thismethodofdistributionindicatestotheemployeesthatitisa“trusted”applicationandit’sOKtoentertheircredentialsintheapp.
Step1:AsktheuserfortheircredentialsThefirststepisaskingtheusertoprovidetheircredentialstotheapplication.Inadditiontoausernameandpassword,Salesforcerequiresthatauserentertheirsecuritytokenwhenloggingintoanappfromanuntrustednetwork,suchasthenetworksusedbypopularmobilephoneserviceproviders.Anapplicationwouldtypicallydisplaythisasathirdfieldforuserinput,inadditiontotheusernameandpassword.
Step2:ExchangethecredentialsforanaccesstokenTheprocessofexchangingcredentialsforanaccesstokenisverysimilartoexchanginganauthorizationcodeforanaccesstokenintheAuthorizationCodeflow.WesimplyneedtomakeaHTTP POSTtotheauthorizationserver,providingthecredentialsandclientinformation.
YoucanfindtheauthorizationserverURLintheAPIprovider’sdocumentation.ForSalesforce,theURLis
https://login.salesforce.com/services/oauth2/token
HerearetherequiredPOSTparameters:
grant_type
Specifiedas“password”forthisflow.
scope
Thedatayourapplicationisrequestingaccessto.ItisnotrequiredforSalesforceandisoptionalforotherAPIs.TheWinter’12versionofSalesforceintroducesoptionalvaluesforthisparameter.
client_id
Thevalueprovidedtoyouwhenyouregisteredyourapplication.Althoughoptionalinthespec,thisvalueisrequiredbySalesforce.RegistrationoftheappisachievedusingtheAppSetup→Develop→RemoteAccessmenu.
client_secret
Thevalueprovidedtoyouwhenyouregisteredyourapplication.Whilethenameofthisparameterimpliesthatthevalueissecret,itissometimesrequiredbyAPIprovidersfornonconfidentialclientssuchasnativemobileapplications.Inthesecases,thevalueisnotactuallyasecret,asitcouldbediscoveredbyusersoftheapplication.
username
Theusernameprovidedbytheresourceowner,encodedasUTF-8.
password
Thepasswordprovidedbytheresourceowner,encodedasUTF-8.ForSalesforce,youneedtoconcatenatethesecuritytokenenteredbytheuserattheendoftheenteredpasswordandpassthecombinedvalueasthevalueofthisparameter.
Here’sanexamplerequestviathecurlcommand-lineHTTPclient:curl -d "grant_type=password" \-d "client_id=3MVG9QDx8IKCsXTFM0o9aE3KfEwsZLvRt" \-d "client_secret=4826278391389087694" \-d "username=ryan%40ryguy.com" \-d "password=_userspassword__userssecuritytoken_" \https://login.salesforce.com/services/oauth2/token
Iftheuser-providedcredentialsaresuccessfullyauthenticated,theSalesforceOAuthauthorizationserverwillreturnanapplication/jsonresponsecontaininganaccess_token:
{ "id":"https://login.salesforce.com/id/00DU0000000Io8rMAC/005U0000000hMDCIA2", "issued_at":"1316990706988", "instance_url":"https://na12.salesforce.com", "signature":"Q2KTt8Ez5dwJ4Adu6QttAhCxbEP3HyfaTUXoNI=", "access_token":"00DU0000000Io8r!AQcKbNiJPt0OCSAvxU2SBjVGP6hW0mfmKH07QiPEGIX"}
Whatdoeachoftheseresponseparametersmean?
access_token
TheaccesstokenusedtoaccesstheAPIonbehalfoftheuserwhoprovidedtheircredentials.Thisistheonlyrequireditemintheresponse.
id(Salesforce-specificvalue)
Theuniqueidentityoftheuser.ThisURLcanalsobeaccessedasanyotherOAuth-protectedresourcetoobtainmoreinformationabouttheuser.TheusermetadataisreturnedasJSONorXML,dependingonthevalueoftheHTTPAcceptheadersentintherequest.
instance_url
TheURLprefixtheclientapplicationshouldusetoaccesstheAPI.ThisresponseparameterisspecifictoSalesforce’simplementation.
signature
AsignatureusedtovalidatethattheidentityURLhasn’tbeenmodifiedsincebeingsentfromtheserver.AlthoughSalesforceissuessignaturesthatcanbeverified,itisn’tstrictlynecessary;instead,theapplicationcanusethebuilt-inprotectionsofHTTPStoensurecommunicationwithSalesforce’sservers.ThisresponseparameterisspecifictoSalesforce’simplementation.
issued_at(Salesforce-specificvalue)
Thetimethesignaturewasgenerated,usedforvalidatingit.
Step3:CalltheAPISincetheOAuthaccesstokenissuedbytheauthorizationflowisasimplebearertokenliketheaccess
tokensprovidedintheotherflows(asdescribedinStep3:CalltheAPI),itcanbeusedsimilarly.YousimplyneedtoprovidetheaccesstokenviaaHTTPAuthorizationheaderorqueryparametervalue,dependingonwhichtheAPIprovidersupports.
Here’sanexamplecurlrequest:curl -d "q=SELECT+name+FROM+Account"\-H 'Authorization: Bearer 00DU0000000Io8r!AQcAQKJ.Cg1dCBCVHmx2.Iu3lroPQBV2P65_jXk'"https://na12.salesforce.com/services/data/v20query"
Step4:RefreshtheaccesstokenAlthoughSalesforcedoesnotsupportrefreshingtheaccesstokenwhenusingthisflow,thespecdoesaccommodateitusingthemethoddescribedinStep4a:Refreshtheaccesstoken.
Itisimportantthatclientshaveawayofrefreshingtheaccesstokenifitisissuedwithonlyashort-termlifespan.Thispreventsdevelopersfromneedingtostoretheprovidedusercredentialswithintheirapplications—oneofthemajorbenefitsofthisflowversustraditionalHTTPBasicaccessauthenticationmechanisms.
Chapter5.ClientCredentialsFlowMostoftheOAuthflowsareforhandlingdelegatedauthorization,whenaresourceownergrantsaccesstoanapplicationtoaccessherdata.However,therearecaseswhentheclientitselfownsthedataanddoesnotneeddelegatedaccessfromaresourceowner,ordelegatedaccesshasalreadybeengrantedtotheapplicationoutsideofatypicalOAuthflow.
Thisflow(showninFigure5-1)workswellforsimilarusecasesasthe“2-legged”flowinOAuth1.0.
Figure5-1.ClientCredentialsflow:Step-by-step
WhenShouldtheClientCredentialsFlowBeUsed?ImagineastorageAPI,suchasGoogleStorageorAmazonS3.You’rebuildinganapplicationthathasresources(datafiles,images,etc.)storedexternallytoyourappusingoneoftheseAPIs.Theapplicationneedstoreadandupdatetheseresources,butactingonbehalfoftheappitselfratherthanonbehalfofanyindividualuser.ThisisaperfectusecasefortheClientCredentialsflow.TheapplicationcanasktheOAuthauthorizationserverforanaccesstokendirectly,withouttheinvolvementofanyenduser.
ThereisanotherrepresentativecasefortheClientCredentialsflow—whenaresourceownerhasgrantedanapplicationaccesstotheirresourcesoutofband,withoutusingatypicalOAuthflow.GoogleprovidesaconcreteusecaseintheGoogleAppsMarketplace.WhenanapplicationislistedontheMarketplace,vendorsgetcredentialsthatrepresenttheirapplicationandalsoregisterthescopesofdatatheyneedaccessto.Whentheapplicationislaterinstalledbyanorganization’sITadministrator,Googleaskstheadministratorwhetherit’sOKtogranttheapplicationaccesstohisorganization’sdata.Whenaccessisapproved,Googlestoresthatorganization“AcmeCorp”hasgrantedaccessto“GoogleCalendarandGoogleContacts”forapplication“TaskManagerPro.”Googledoesnotissueanytokenstotheapplication.Whentheapplicationtriestoaccessdatainthefuture,Googlesimplylooksupwhethertheapplicationisallowedaccesstodatafortheparticularorganization.
WhatAPIsSupporttheClientCredentialsFlow?Whiletheprecedingparagraphsdescribesomepotentialusecasesforthisflow,theseproviders(GoogleandAmazon)havenotyetimplementedtheClientCredentialsflowinOAuth2.0.However,Facebookhasimplementedthisflowforitsapplications,tobeabletoperformAppLogin.AppLoginisrequiredforcertainFacebookAPIcalls,includingtheabilitytogetappstatisticsanduserdemographicsfromtheAppInsightsservice.
HowDoestheClientAuthenticate?Thisflowisreliantupontheclientbeingabletoproperlyauthenticatewiththeauthorizationserverandtheclient’sauthenticationcredentialsremainingconfidential.Inordertoauthenticate,theclientcanpasstheclient_idandclient_secrettotheauthorizationserverasPOSTparametersintheaccesstokenrequestorcanuseaHTTPBasicAuthenticationheader.Theauthorizationservercanalsoauthenticatetheclientusingothermechanisms,suchasapublic/privatekeypair,SSL/TLSclientauthentication,andthelike.
SecurityPropertiesDependingonthepreciseusecasetheClientCredentialsflowisusedfor,asinglesetofcredentialsforaclientcouldprovideaccesstoalargeamountofdata.Themoredataasinglesetofcredentialshasaccessto,thegreatertheriskifthecredentialsbecomecompromised.Itisextremelycriticalthatthecredentialsusedtoauthenticatetheclientbekepthighlyconfidential.Ideally,thesecredentialswouldalsoberegularlyrotated.
Step-by-StepTodemonstratethisflow,we’lluseFacebook’simplementationofAppLoginwiththeAppInsightsservice.
Step1:Exchangetheapplication’scredentialsforanaccesstokenTheapplicationneedstorequestanaccesstokenfromtheauthorizationserver,authenticatingtherequestwithitsclientcredentials.
Youcanfindtheauthorizationserver’stokenURLintheAPIprovider’sdocumentation.ForFacebook,theURLis
https://graph.facebook.com/oauth/access_token
HerearetherequiredPOSTparameters:
grant_type
Specifiedas“client_credentials”forthisflow.
client_id
Thevalueprovidedtoyouwhenyouregisteredyourapplication.
client_secret
Thevalueprovidedtoyouwhenyouregisteredyourapplication.
Here’sanexamplerequestviathecurlcommand-lineHTTPclient:curl -d "grant_type=client_credentials\&client_id=2016271111111117128396\&client_secret=904b98aaaaaaac1c92381d2" \https://graph.facebook.com/oauth/access_token
Iftheclientcredentialsaresuccessfullyauthenticated,anaccesstokenisreturnedtotheclient.AsFacebookhasimplementedanearlierversionoftheOAuth2.0specificationasofthetimeofthiswriting,itreturnstheaccess_tokeninthebodyoftheresponseusingformurl-encoding:
access_token=2016271111111117128396|8VG0riNauEzttXkUXBtUbw
Thelatestdraftofthespec(v22)statesthattheauthorizationservershouldinsteadreturnanapplication/jsonresponsecontainingtheaccess_token:
{ "access_token":"2016271111111117128396|8VG0riNauEzttXkUXBtUbw"}
Theaccess tokenisthenusedtoaccesstheAPIonbehalfoftheapplicationitself.
Step2:CalltheAPISincetheOAuthaccesstokenissuedbytheClientCredentialsflowisabearertokenliketheaccesstokensprovidedintheotherflows,itcanbeusedsimilarly.YousimplyneedtoprovidetheaccesstokenviaaHTTPAuthorizationheaderorqueryparametervalue,dependingonwhichtheAPIprovidersupports.
Here’sanexamplecurlrequest,usingaqueryparametertopasstheaccesstoken:curl "https://graph.facebook.com/202627763128396/insights?\access_token=2016271111111117128396|8VG0riNauEzttXkUXBtUbw"
FacebooksupportspassingtheaccesstokenasaHTTPAuthorizationheaderaswell,butusingtheolderAuthorization: OAuth tokenvalueinsteadofAuthorization: Bearer tokenvalue.
WhentheAccessTokenExpiresTheClientCredentialsflowtypicallyprovidesalong-livedaccesstoken.Theauthorizationservermayindicateanexpires_intime;however,theprotocoldoesnotsupportissuingarefreshtokeninresponsetotheClientCredentialsflow.Instead,theapplicationsimplyasksforanewaccesstokenifthecurrentoneexpires.
Chapter6.GettingAccesstoUserDatafromMobileAppsTherearetwomainclassesofmobileapplications:mobile-optimizedwebappsusingHTML5andotherwebtechnologiesandnativemobileapplications.Whilemobile-optimizedwebappscanusethetraditionalOAuthclient-sideorWebApplicationflowswithsomespecialconsiderationforuserexperience,nativemobileapplicationsrequireadditionalconsiderations.
WhyYouShouldUseOAuthforNativeMobileAppsWhenbuildinganativemobileapp,therearetwoprimaryreasonsyoushouldconsiderusingOAuth:
AccesstoyourownAPIs
Manymobileapplicationshavebackendserversthattheyusetokeeptrackofuserdata.Perhapsyourappisagameandstoreshighscoresandlevelcompletiondatainaserver-sidedatabasetoenablesocialfunctionalityorsupportingplayingthegameonmultipleplatforms.Inthiscase,yourappneedstocommunicatewiththebackendusinganAPI,typicallyaREST-basedHTTPAPI.OAuthisagreatwaytohandleAPIauthorizationforthesetypesofapplications,anditenablesyoutobuildandmaintainonlyoneinterfaceforuserstologintoyourapplication,whetherthey’reontheWeborusingyournativemobilecompanionapp.
AccesstoAPIsfromotherproviders
SomeAPIprovidersmayrequireyoutouseOAuthforAPIauthorization.However,forthosethatdon’t,therearestillseveralgreatreasonsyouwanttouseOAuthfornativemobileapps:youhaveanobligationtohelpusersstaysafeandalsoadesiretomakeyourapplicationeasytousebyallusers.Askingusersfortheirpasswordforthird-partyservicesreinforcesthispatternandmakesusersmorevulnerabletophishingattempts.Thisfurtherrequiresthatyourapphaveaccesstotheuser’sentireaccount(asopposedtoalimitedscopeofdata)andrequiresyourapptostoretheuser’scredentialsonthedeviceforlong-livedaccess,potentiallyleavingthemopentocompromise.AnotherprimaryreasonthatyouwanttoconsiderusingOAuthisthatsomeusersatspecificAPIprovidersmaysimplynotbeabletodelegateaccesstoyourappwithatypicalusernameandpasswordbecausetheyuseasecond-factorauthenticationscheme(suchasaone-timepasswordkeytoken)ortheiraccountisfederatedtoanotheridentityprovider(viaOpenID,SAML,etc.).
WhatFlowShouldBeUsedforNativeMobileApps?TheavailableflowsfornativemobileappswilllikelyberestrictedbasedonwhatflowsaresupportedbyyourAPIprovider.However,thereareafewquestionsyoucanconsiderwhendecidingwhatflowtouse.
DoYouHaveaMobileBackendWebServerforYourApplication?Yes:Ifyouhaveamobilebackendwebserverforyournativeapp,youcanuseoneofthetypicalOAuthflowsforwebapplications:theclient-side(implicit)flowortheflowforserver-sidewebapps.Thesameconsiderationsapply:Doyouneedlong-lived“offline”accessfromyourmobileapp’sbackendserver?Usetheserver-sidewebappflow.Ordoyouneedshort-livedone-timeaccessdirectlyfromthenativeapp?Usetheclient-sideimplicitflow.
Whenusingtheserver-sidewebappflowandpassinganauthorizationcodetoyourserver,theuseroftheappwillstillneedtobeauthenticatedtotheappbackend,similartohowauserisauthenticatedtowebapplicationserversusingsessioncookies.
No:Ifyourapplicationdoesnothaveamobilebackendwebserverpoweringit,youneedtousesometypeofnativeapplicationflow.Thiscanbeverysimilartotheserver-sidewebappflowortheclient-sideimplicitflow,buttherearetworestrictions:youdon’thaveawebservertousefortheredirect_uri,andyoushouldmaintaintheconfidentialityofanyclient_secretvalues,whicharesometimesrequiredfortheserver-sideflow.
Dependingonthemobileplatformyou’rebuildingonandtheAPIprovideryou’reusing,youcanuseacustomURIschemesuchasmy-mobile-app://oauth/callbackfortheredirect_uriinordertoreturntheauthorizationcodeoraccess_tokentoyourapplication.However,onsomeplatforms,thesecustomURIschemescanberegisteredbymultipleapplications(andtheiruniquenessisnotguaranteed),sothereisariskthatthetokenscouldbeinterceptedbythewrongapponthedeviceandusedmaliciously.It’salsopossiblethatyourAPIproviderrequirespreregistrationoftheseredirect_urivaluesanddoesnotacceptvaluesusingcustomURIschemes.
TherearealsosomeAPIproviderssupportinganativeclientflow.Withthenativeclientflow,aspecialredirect_urivalueisusedtosendtheauthorizationcodeoraccesstokentoawebpagehostedbytheOAuthauthorizationserver.Theusercanthencopy/pastethisvalueintotheapplicationortheapplicationcanprogrammaticallygrabthevaluefromthebodyorwindowtitleandclosethewebbrowserwindow.
Thecurrentlyproposedspecialredirect_urivalueforthenativeclientflowisurn:ietf:wg:oauth:2.0:oob.Figure6-1showsanexampleresultwebpageaftertheuserapprovesaccesstotheirdata.Inmostcases,theuserwouldneverseethispage,however,becausetheapplicationwouldgrabtheaccesstokenandclosethewindowbeforeitisvisible.
Figure6-1.Google’sresponsepagewhenusingtheOOBredirect_urifornativeclients
The(Ugly)WebBrowserManymobileapplicationdevelopershaveobjectedtousingOAuthfortheirnativeapplicationsbecauseitrequireseitherembeddingaWebVieworopeningupthesystemwebbrowseronthedevice.Theydon’tvieweitheroftheseasgoodoptions,asawebbrowseroftenfeelsdifferentthananativeUI.
Thisisareasonableconcern,thoughwealwaysneedtobalancesecurityandusability.WeshouldexpectthattheuserexperiencefortheseOAuthbrowser-basedflowswillcontinuetoimprovealongwithincreasedpervasivenessofHTML5technologyandmobilewebUXdesigntechniques.
EmbeddedWebViewTheembeddedWebViewhasbecomeapopularwaytohandleOAuthauthorizationgrantsfornativemobileapplications.Insteadofopeningupthesystemwebbrowser(viaanIntentonAndroidorUIApplicationoniOS),theembeddedWebViewsimplyincludesabrowserwithinthemainapplicationwindow.Thismechanismleadstoasmallercontextswitchfortheuser,whileatthesametimeprovidingthenativeappgreatercontroloverthewebbrowser.
Primaryadvantage
WebViewsareeasilycontrolledbythenativeapplication.ThisenablestheapplicationtoeasilyaccesstheOAuthaccesstokenorauthorizationcodebyexaminingthecookiestoreorthetitleoftheapplicationwindow,withoutworryingabouttheissuesofregisteringacustomURLscheme.
Somedisadvantages
WebViewsdon’tdisplaythetrustindicatorspresentinthesystemwebbrowser(suchastheSSL/TLSlockindicatingcertificatechainvalidationandtheURLofthesite).UsersmaybepromptedtoentertheircredentialstologintotheOAuthauthorizationprovider.Thisresultsinusersbeingmorevulnerabletophishingattacksifevilappsaredeployedontouserdevices.
Withseparatecookieandhistorystores,theuserisnotloggedintoanyaccounts.ThismeansthattheymustlogintotheOAuthAuthorizationServerbeforegrantingaccesstoanapp,andenteringcredentialsonmobiledevicescansometimesbeapainfulexperience.
SystemWebBrowserOpeningupthesystemwebbrowserseemslikethenaturalwaytosendauserthroughanOAuthgrantflow,butaswiththeembeddedWebView,therearebothadvantagesanddisadvantagestothistechnique.
Someadvantages
Thesystemwebbrowserusesthesystemcookiestore.IfyourapplicationintegrateswithapopularAPIprovider,it’slikelythattheuserisalreadyloggedintotheprovider—resultinginasimplesingle-clickgrantprocess.Usersdon’tneedtoretypetheirpassword.
Usershavegreatersecurityassuranceswiththesystemwebbrowser,asthey’reaccustomedtothetypicalsecurityindicators(suchastheSSL/TLSlockandtheURLofthesite).Thismakesuserslessvulnerabletophishing.
Somedisadvantages
Usingthesystemwebbrowserrequiresthattheuserbereturnedtothenativeappaftergrantingaccess.Asmentionedabove,thistypicallydoneusingacustomURIschemesuchasmy-mobile-app://oauth/callbackfortheredirect_uri.Becausethereisnocentralregistryofthesecustomschemes,othermaliciousapplicationsinstalledonthedevicemaybeabletointercepttheOAuthaccesstokensorauthorizationcodes.
Thehistorystoreofthesystemwebbrowsercannotbecontrolledbythenativeapp,leadingtopotentialcompromiseofOAuthaccesstokensiftheimplicitflowisused.Whilethisisalsoaproblemondesktopwebbrowsers,it’smoreofaconcernwithmobiledevices,whicharemoreportableandthusmoresusceptibletolossandtheft.ThisriskisusuallymitigatedbytheshortvalidityofOAuthaccesstokens.
EnhancedMobileAppAuthorizationforSpecificProvidersSomeOAuthprovidershavebuiltspecialmobilelibrariesorapplicationstomakedoingOAutheasierondevicesandtoimprovetheuserexperience.
ForGoogleOnitsAndroidoperatingsystem,GoogleprovidesaservicecalledtheAccountManager.OriginallythisservicewasdesignedtoallowapplicationstorequestauthtokensforGoogleAPIsusingtheproprietaryClientLoginmechanism.However,thisservicehasbeenupdatedtosupportgettingOAuth2.0accesstokensforGoogleAPIs.
InordertogetanOAuth2.0accesstoken,yousimplyneedtocallAccountManager.getAuthToken()torequestatokenusinganauthTokenTypeofoauth2:<scope>.Forexample,torequestaccesstotheGoogleTasksAPI,specifyanauthTokenTypeofoauth2:https://www.googleapis.com/auth/tasks.Unfortunately,thisliteralstringwillbepresentedtouserswhenthey’reaskedtograntaccess,sousingthistechniqueisnotrecommended.However,forsomeAPIs,suchasGoogleTasks,therearealiasessuchasManageYourTasksthatcanbeusedinplaceoftheoauth2:<scope>valuetoproduceamuchfriendlierrequest.
AfteryoucallgetAuthToken(),theaccountmanagerwillasktheusertoapproveordenytherequestusinganativeapplicationprompt.Iftheuserapprovestherequest,theapplicationwillbeissuedanaccess_tokenvalue,whichcanbeusedinAPIrequests.
TheGoogleTasksAPIteamhascreatedanarticlewithmoredetailsonusingthistechnique.AlthoughotherGoogleAPIsmaynothaveuser-friendlyaliasessuchasManageYourTasks,thegeneraltechniquesdescribedinthearticlewillstillapply.
GoogledoesnothavesimilarfunctionalityavailableforiOSatthetimeofthiswriting.However,GoogledoeshaveaclientlibraryforObjective-CwhichmakescreatinganembeddedWebViewOAuthflowveryeasytoimplementoniOS.
ForFacebookFacebookhasSDKsavailableforbothAndroidandiOSthatautomaticallyprompttheuserforrequestedpermissions.
OnAndroid,youcallFacebook.authorize()andwaitfortheusertoapprovetheauthorizationrequest.Aftertheuserapproves,youcancallFacebook.getAccessToken()togetanaccesstokenforusewiththerequestedAPIs.
Chapter7.OpenIDConnectAuthenticationNearlyeverywebapplicationpromptsuserstocreateanaccountandlogin.Inordertocreateanaccount,usersareaskedtoprovidetheirname,theiremailaddress,apassword,andpasswordconfirmation.Notonlydoesthistakealotofeffortfortheuser(50+keystrokes),butitalsocreatessecurityconcerns,asusersoftencreatethesamepasswordonmultiplesitesandsomesitesdonotproperlysecurethesecredentials.
OpenIDexiststoenablefederatedidentity,whereusersareabletoauthenticatewiththesameidentityacrossmultiplewebapplications.Bothusersandwebapplicationstrustidentityproviders,suchasGoogle,Yahoo!,andFacebook,tostoreuserprofileinformationandauthenticateusersonbehalfoftheapplication.Thiseliminatestheneedforeachwebapplicationtobuilditsowncustomauthenticationsystem,anditmakesitmucheasierandfasterforuserstosignupandsignintositesaroundtheWeb.
OpenIDConnectisthenext-generationversionofOpenID.ThedevelopmentofOpenIDConnecthastakenintoaccounttwokeyconcepts:
Passingpermissiontoaccessauthenticationinformation(theuser’sidentity)toasiteisverysimilartopassingalongdelegatedaccesstoauser’sdata(suchastheircalendar).Developersshouldn’thavetouseentirelydifferentprotocolsforthesetwodifferentusecases—especiallybecausemanydevelopersneedtohandlebothintheirapplications.
Thespecificationshouldbemodular—enablingspeccompliancewithoutrequiringimplementationofautomateddiscovery,associations,andothercomplexbitsincludedinthepreviousversionsofOpenID.
ThebasicflowforOpenIDConnectis:
1. TheapplicationrequestsOAuth2.0authorizationforoneormoreoftheOpenIDConnectscopes(openid,profile,email,address)byredirectingtheusertoanidentityprovider.
2. AftertheuserapprovestheOAuthauthorizationrequest,theuser’swebbrowserisredirectedbacktotheapplicationusingatraditionalOAuthflow.TheappmakesarequesttotheCheckIDEndpoint.Thisendpointreturnstheuser’sidentity(user_id)aswellasotherbits,suchastheaudandstate,whichmustbeverifiedbytheclienttoensurevalidauthentication.
3. Iftheclientrequiresadditionalprofileinformationabouttheuser,suchastheuser’sfullname,picture,andemailaddress,theclientcanmakerequeststotheUserInfoEndpoint.
BecauseOpenIDConnectisbuiltontopofOAuth2.0andisdesignedasamodularspecification,it’smucheasierforyoutoimplementfederatedauthenticationforyourwebsiteinacompliantway.SincethisisaGettingStartedbook,thischapterwillprimarilydiscusstheOpenIDConnectBasicClientimplementation.
IDTokenWithOpenIDConnectauthentication,thereisanadditionaltypeofOAuthtoken:anIDtoken.TheIDtoken,orid_token,representstheidentityoftheuserbeingauthenticated.Thisisaseparatetokenfrom
theaccesstoken,whichisusedtoretrievetheuser’sprofileinformationorotheruserdatarequestedduringthesameauthorizationflow.
TheIDtokenisaJSONWebToken(JWT),whichisadigitallysignedand/orencryptedrepresentationoftheuser’sidentityassertedbytheidentityprovider.InsteadofusingcryptographicoperationstovalidatetheJSONWebToken,itcanbetreatedasanopaquestringandpassedtotheCheckIDEndpointforinterpretation(seebelow).ThisflexibilitykeepswiththespiritofOAuth2.0andOpenIDConnectbeingsignificantlyeasiertousethantheirpredecessors.
SecurityPropertiesAlthoughtheenduserflowisquitesimilar,thesecurityprecautionsnecessaryforauthenticationaremuchdifferentthanthoseforauthorizationbecauseofthepotentialforreplayattacks.Replayattacksoccurwhenlegitimatecredentialsaresentmultipletimesformaliciouspurposes.
Therearetwomaintypesofreplayattackswewishtoprevent:
Anattackercapturingauser’sOAuthcredentialsastheylogintoasiteandusingthemlateronthesamesite.
ArogueapplicationdeveloperusingtheOAuthtokenauserwasissuedtologintotheirmaliciousappinordertoimpersonatetheuseronadifferentlegitimateapp.
TheOAuth2.0specificationrequirestheOAuthendpointandAPIstobeaccessedoverSSL/TLStopreventman-in-the-middleattacks,suchasthefirstcase.
PreventingrogueapplicationdevelopersfromreplayinglegitimateOAuthcredentialstheirappreceivedinordertoimpersonateoneoftheirusersonanotherapprequiresasolutionspecifictoOpenIDConnect.ThissolutionistheCheckIDEndpoint.TheCheckIDEndpointisusedtoverifythatthecredentialsissuedbytheOAuthproviderwereissuedtothecorrectapplication.
ItisrecommendedthatalldevelopersusetheCheckIDEndpointordecodetheJSONWebTokentoverifytheassertedidentity,thoughthisisnotstrictlynecessaryinsomecaseswhentheapplicationusestheserver-sideWebApplicationflowandtheUserInfoEndpointprovidesallrequiredinformation.
Theserver-sideWebApplicationflow,whenimplementedasperthespecification,onlyissuesanauthorizationcodethroughtheuser’swebbrowser.Thewebapplicationshouldnoteveracceptanaccesstokenoridentitytokendirectlyfromthebrowser.Theaccesstokenandidentitytokenareretrievedbyexchangingtheauthorizationcodeinaserver-to-serverrequest.Sincethisexchangerequirestheserver-to-servercalltobeauthenticatedwiththeclientIDandclientsecretoftheappwhichtheauthorizationcodewasissuedfor,theOAuthtokenservicewillnaturallypreventanappfromaccidentallyusinganauthorizationcodeissuedtoanotherapp.
Alternatively,theclient-sideWebApplicationflowissuesanaccesstokenandidentitytokendirectlytotheappthroughthebrowserusingahashfragment.TheaccesstokenandidentitytokenareoftensenttothebackendwebserverusingJavaScriptinordertoauthenticatetheuser.Inthiscase,thewebservermusteithercryptographicallyverifytheIDTokenorcalltheCheckIDendpointtoverifyitwasissuedtothecorrectapplication.Thisiscalled“verifyingtheaudience”ofthetoken.SeeCheckIDEndpointformoreinformation.
ObtainingUserAuthorizationTheprocessofobtaininguserauthorizationforOpenIDConnectisnearlyidenticaltotheprocessofobtainingauthorizationforanyOAuth2.0enabledAPI.Youcanuseeithertheclient-sideimplicitflow(asdescribedinChapter3)ortheserver-sidewebappflow(asdescribedinChapter2).
Aswithanyusageoftheseflows,theclientgeneratesaURLpointingattheOAuthAuthorizationEndpointandredirectstheusertothatURL.Thefollowingparametersarepassed:
client_id
Thevalueprovidedtoyouwhenyouregisteredyourapplication.
redirect_uri
Thelocationtheusershouldbereturnedtoaftertheyapprovetheauthenticationrequest.
scope
openidforabasicOpenIDConnectrequest.Ifyourclientneedsaccesstoadditionalprofileinformationfortheuser,additionalscopescanbeprofiledinthisspace-delimitedstring:profile,email,address.
response_type
id_tokentoindicatethatanid_tokenisrequiredfortheapplication.Additionally,aresponsetypeoftokenorcodemustbeincluded,separatingthetworesponsetypesbyaspace.tokenindicatestheclient-sideWebApplicationflow,whilecodeindicatestheserver-sideWebApplicationflow.
nonce
Auniquevalueusedbyyourapplicationtoprotectagainstreplayandcross-siterequestforgery(CSRF)attacksonyourimplementation.Thevalueshouldbearandomuniquestringforthisparticularrequest,unguessableandkeptsecretintheclient(perhapsinaserver-sidesession).ThisidenticalvaluewillbeincludedintheIDtokenresponse(seebelow).
ThefollowingisanexampleofacompleteAuthorizationEndpointURL,usingtheclient-sideimplicitflow:
https://accounts.example.com/oauth2/auth? scope=openid+email& nonce=53f2495d7b435ac571& redirect_uri=https%3A%2F%2Foauth2demo.appspot.com%2Foauthcallback& response_type=id_token+token& client_id=753560681145-2ik2j3snsvbs80ijdi8.apps.googleusercontent.com
Aftertheuserapprovestheauthenticationrequest,theywillberedirectedbacktotheredirect_uri.Sincethisrequestusestheimplicitflow,theredirectwillincludeanaccesstokenthatcanbeusedwiththeUserInfoEndpointtoobtainprofileinformationabouttheuser.Additionally,andspecifictoOpenIDConnect,theredirectwillalsoincludeanid_token,whichcanbesenttotheCheckIDEndpointtogettheuser’sidentity.
Here’sanexampleredirect:https://oauth2demo.appspot.com/oauthcallback# access_token=ya29.AHES6ZSzX
token_type=Bearer& expires_in=3600& id_token=eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiY...
TheclientthenneedstoparsetheappropriateparametersfromthehashfragmentintheURLandcalltheCheckIDEndpointtovalidatetheresponse.
CheckIDEndpointTheCheckIDEndpointexiststovalidatetheid_tokenreturnedalongwiththeOAuth2.0access_tokenbyensuringthatitwasintendedforthecorrectclientandisusedbytheclienttobeginanauthenticatedsession.Asdescribedabove,thischeckisrequiredfortheimplicitflowforclient-sideapplications(describedinChapter3).Ifthischeckisn’tdonecorrectly,theclientbecomesvulnerabletoreplayattacks.
Here’sanexampleCheckIDendpointrequest:https://accounts.example.com/oauth2/tokeninfo? id_token=eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiY...
Andtheresponse:{ "iss" : "https://accounts.example.com", "user_id" : "113487456102835830811", "aud" : "753560681145-2ik2j3snsvbs80ijdi8.apps.googleusercontent.com", "exp" : 1311281970 "nonce" : 53f2495d7b435ac571}
IftheresponseisreturnedwithoutastandardOAuth2.0error,thefollowingchecksneedtobeperformed:
Verifytheaudvalueintheresponseisidenticaltotheclient_idusedintheAuthorizationrequest.
VerifythatthenoncevalueintheresponsematchesthevalueusedintheAuthorizationrequest.
Ifthisverificationiscompletedsuccessfully,theuser_idisknowntorepresenttheuniqueidentifierfortheauthenticateduser,withinthescopeoftheissuer(iss).Ifstoringtheidentifierinauserdatabasetableandmultipleidentityprovidersaresupportedbyyourapplication,itisrecommendedthatbothvaluesbestoreduponaccountcreationandquerieduponeachsubsequentauthenticationrequest.
UserInfoEndpointWhiletheCheckIDEndpointwillreturnauniqueidentifierfortheuserauthenticatingtoyourapplication,manyapplicationsrequireadditionalinformation,suchastheuser’sname,emailaddress,profilephoto,orbirthdate.ThisprofileinformationcanbereturnedbytheUserInfoEndpoint.
TheUserInfoEndpointisastandardOAuth-authorizedRESTAPI,withJSONresponses.AswhenaccessinganyotherAPIusingOAuth,theaccess_tokencanbepassedeitherasanAuthorizationheaderorasaURLqueryparameter.
Here’sanexampleUserInforequest:GET /v1/userinfo HTTP/1.1Host: accounts.example.comAuthorization: Bearer ya29.AHES6ZSzX
Withtheresponse:{ "user_id": "3191142839810811", "name": "Example User", "given_name": "Example", "family_name": "User", "email": "user@example.com", "verified": true, "profile": "http://profiles.example.com/user", "picture": "https://photos.profiles.example.com/user/photo.jpg", "gender": "female", "birthday": "1982-02-11", "locale": "en-US"}
OpenIDConnectdoesnotdefineanyspecificprofilefieldsasrequiredanddoesallowforadditionalprofilefieldstobeincludedintheresponse.
PerformanceImprovementsTheobjectiveofthecalltotheCheckIDEndpointistoverifythelegitimacyoftheid_token.However,thisrequiresanadditionalHTTPrequesttotheOpenIDConnectidentityprovider.Thisadditionalrequestcanbeavoidedsincetheid_tokenisreturnedasasignedJSONWebToken(JWT)insteadofasanopaqueblob.TheJWTincludesthesameinformationthatistypicallyreturnedbytheCheckIDEndpoint,butthevalueisalsocryptographicallysignedbytheserverinawaythatcanbevalidatedbytheclient.
ThisgivestheclienttheoptiontoverifythesignatureusingtheJWT(forbestperformance)orsimplycalltheCheckIDEndpointiftheclientwantstoavoidcryptography.
PracticalOpenIDConnectSincetheOpenIDConnectspecificationisstillunderactivedevelopment,experimentalimplementationsbyidentityprovidersstilldifferfromthespecification.Herearesomeexamplerequestsandresponsesusingtheseexperimentalimplementations.
ForGoogleGoogle’sOpenIDConnectimplementation(seeFigure7-1)usesthefollowingEndpoints:
CheckID
https://www.googleapis.com/oauth2/v1/tokeninfo
UserInfo
https://www.googleapis.com/oauth2/v1/userinfo
Googledoesnothavethegenericopenidscope,butitsupportsthefollowingmainscopesforitsOpenIDConnectimplementation:
https://www.googleapis.com/auth/userinfo.email
Profile
https://www.googleapis.com/auth/userinfo.profile
Here’sanexampleauthorizationURLforGoogle’sOpenIDConnectimplementation:https://accounts.google.com/o/oauth2/auth? scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&
state=ABC123456& redirect_uri=https%3A%2F%2Foauthssodemo.appspot.com%2Foauthcallback& response_type=token%20id_token& client_id=8819981768.apps.googleusercontent.com
Figure7-1.Googleaskingifit’sOKtoshareinfowithexampleapp“OAuthSSORelyingParty”
Inthisexample,we’respecifyingaresponse_typeoftoken id_token,indicatingthatwe’relookingfor
bothanIDtokenandatraditionalOAuth2.0accesstoken(viatheimplicitflow).Aftertheuserapprovestherequestbyclicking“AllowAccess,”Googleredirectsbacktotheredirect_uriandincludesanid_tokenandanaccess_tokeninthehashfragmentoftheURL.Theid_tokenisaJSONWebToken(JWT)andcontainstheuser’sID.ThisIDtokencanbevalidatedbycomparingacryptographicsignatureortheCheckIDEndpointcanbecalled.Forsimplicity,we’llshowhowtocalltheCheckIDEndpoint.Here’sanexamplerequest:
https://www.googleapis.com/oauth2/v1/tokeninfo? id_token=eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiY...
Here’stheresponse:{ "issued_to" : "8819981768.apps.googleusercontent.com", "user_id" : "113487456102835830811", "audience" : "8819981768.apps.googleusercontent.com", "expires_in" : 3465}
AftertheCheckIDresponseisproperlyvalidatedbyensuringit’sbeenissuedforthecorrectapplication(bycomparingthevalueoftheissued_toparametertotheapp’sclientID),theappmaywishtoobtainadditionalprofileinformationabouttheuser.Thisinformation,suchastheuser’snameoremailaddress,canbeobtainedasaJSONresponsefromtheUserInfoEndpoint.TheOAuthaccess_tokenmustbesenttoauthorizetherequest.Here’sanexamplerequest:
GET /oauth2/v1/userinfo HTTP/1.1Host: www.googleapis.comAuthorization: Bearer ya29.AHES6ZSzX
Here’stheresponse:{ "id": "110634877589748180443", "email": "ryan.boyd@gmail.com", "verified_email": true, "name": "Ryan Boyd", "given_name": "Ryan", "family_name": "Boyd", "link": "http://profiles.google.com/110634877589748180443", "picture": "https://lh6.googleusercontent.com/-XC1Cwt4OgfY/AAAAAAAAAAI/AAAAAAAACR8/SU9W99JQFvc/photo.jpg", "gender": "male", "birthday": "0000-10-05", "locale": "en-US"}
You’llnoticethattheresponseindicatesmybirthyearas0000.I’mnotthatold;Googleusesthisspecialvaluetoindicatethatthebirthyearisnotshared.
ForFacebookFacebook’simplementationofidentityusingOAuth2.0isn’tdocumentedasbeingOpenIDConnect.However,itworkssimilarlytothespecification,withafewminordifferencestoaccountforinclientcode.
FacebookusesthefollowingEndpoint:
UserInfo
https://graph.facebook.com/me
FacebookdoesnotprovideCheckIDEndpointfunctionality,andforthisreasonIrecommendusingonlytheAuthorizationCodeflowforserver-sideapplications(describedinChapter2)andnottheimplicitflowforclient-sideapplications.Ifyouusetheclient-sideWebApplicationflow,you’llhavenoabilitytoverifytheaccesstokenwasintendedforusebyyourapplication,andthuscanleaveyourappvulnerabletoreplayattacks.
HerewecanseeanexampleauthorizationURLforFacebook’sOpenIDConnectimplementation:https://www.facebook.com/dialog/oauth? client_id=202627763128396& redirect_uri=https%3A%2F%2Foauth2demo.appspot.com%2Foauthcallback& state=ABC123456
Sinceascopeisnotspecified,Facebookdefaultstorequestingauthorizationforpublicprofileinformation.Additionalinformationcanberequestedbyspecifyingscopevaluessuchasemail,read_stream.NoticethatFacebookusescomma-delimitedscopevaluesinsteadofspace-delimitedvaluesasdefinedbythelatestOAuth2.0specification.
Sincearesponse_typeisnotspecified,FacebookdefaultstotheAuthorizationCodeflowforserver-sidewebapplications.Ifyouwishtousetheimplicitflowforclient-sidewebapplications,specifyaresponse_type=token,thoughthisisnotrecommended.
AsistypicalwiththeAuthorizationCodeflowforserver-sidewebapplicationsdescribedinChapter2,theuser’sbrowserwillberedirectedtotheapplication’sredirect_uriaftertheuserapprovesaccess.TheredirectURLwillincludeanauthorizationcodeinthecodequeryparameter.TheapplicationthenneedstoexchangetheauthorizationcodeforanaccesstokenbymakingarequesttotheTokenEndpoint.
WhiletheauthorizationcodeexchangetypicallyusesaHTTPPOST,FacebookalsosupportsusingaHTTPGET:
https://graph.facebook.com/oauth/access_token? client_id=202627763128396& redirect_uri=https%3A%2F%2Foauth2demo.appspot.com%2Foauthcallback& client_secret=YOUR_APP_SECRET&code=123456
Sincewe’reusingtheAuthorizationCodeflowforserver-sidewebapplications,thereisnoneedtodoaCheckIDrequest.ThisisbecausetheAuthorizationCodeflowrequirestheapplication’scredentialstobesentsecurelytotheserverwhenexchanginganauthorizationcodeforanaccesstoken,resultinginanautomaticcheckthattheauthorizationcodewasissuedtothecurrentclient.However,theapplicationmustkeeptheaccesstokenconfidentialontheserverandpreventtrustinganyaccesstokendirectlysentbytheuser,ortheapplicationcouldbevulnerabletothesametypeofreplayattackthattheCheckIDendpointwasdesignedtoprevent.
Atthispoint,theapplicationcanobtainprofileinformationfortheuserviathemeendpointoftheGraphAPI.Here’sanexamplerequest:
https://graph.facebook.com/me? access_token=123456abc123456abc
Here’stheresponse:{ "id":"545296355", "name":"Ryan Boyd", "first_name":"Ryan",
"last_name":"Boyd", "link":"http:\/\/www.facebook.com\/rboyd", "username":"rboyd", "hometown":{ "id":"114952118516947", "name":"San Francisco, California" }, "location":{ "id":"114952118516947", "name":"San Francisco, California" }, "gender":"male", "email":"ryan\u0040ryguy.com", "timezone":-8, "locale":"en_US", "verified":true, "updated_time":"2011-06-03T18:37:40+0000"}
OpenIDConnectEvolutionTheprotocolislikelytochangeafterreceivingfeedbackfrombothidentityprovidersandrelyingparties.InformationonthecurrentDeveloperPreviewcanbefoundontheOpenIDFoundationsite,includingthedetailedspecificationsandmailingliststofollowdevelopmentofthespecifications.
Chapter8.ToolsandLibrariesAlthoughOAuth2.0isrelativelyyoung,therearestillavarietyoftoolsandlibrariesavailablefordeveloperstomakeusingiteasier.
Google’sOAuth2.0PlaygroundGooglehasbuiltanewversionofitsOAuthPlaygroundtoolforOAuth2.0(seeFigure8-1).TheOAuth2.0Playgrounddemonstratesthethree-stepprocessforatypicalserver-sidewebapplicationAuthorizationCodeflow:gettinganauthorizationcode,exchangingitforanaccesstoken,andmakingAPIrequests.ItalsosupportstheImplicitflowforclient-sidewebapplications.
WhilethedefaultconfigurationistouseGoogle’sAPIsandOAuthendpoints,thetooldoesenableyoutospecifyacustomclientID,clientsecret,andcustomendpoints.SalesforcehasbloggedabouthowtousethetoolwiththeirAPIs.
Figure8-1.Google’sOAuthPlayground
NOTE
ThistoolismadeavailablebyGoogleforeducationalandtestingpurposes.WhileitexposestheOAuthaccesstokentothewebbrowser(andresourceowner),thisshouldnotnormallybedonewhenusingtheAuthorizationCodeflowandconfidentialclients.Also,specifyingcustomclientIDandclientsecretvaluesrequiresthosecredentialsbesenttotheOAuthPlaygroundserver.
Google’sTokenInfoEndpointGoogle’sendpointfortheCheckIDstepofOpenIDConnectcanbeusedtovalidateanyOAuth2.0tokenissuedbyGoogle.Theendpointathttps://www.googleapis.com/oauth2/v1/tokeninfoisasimpleread-onlyAPI.Togetthescopeandexpirationdateofatoken,makeaHTTPrequesttotheendpointandpassanOAuthaccesstokenastheaccess_tokenqueryparameteroranIDtokenastheid_tokenparameter.
Apigee’sConsoleTheApigeeConsoleenablesexploringAPIsfrom20+APIproviders,suchasFacebook,Twitter,Salesforce,andSoundCloud.ForthoseAPIssupportingOAuth,itperformsatypicalOAuthflow,thoughwithoutexposingtheprotocol-leveldetailsoftheOAuthexchange.AfterOAuthauthorizationisgrantedusingavarietyofversionsoftheOAuth1.0andOAuth2.0draftspecifications,itprovideseasyaccesstocallAPIsbyselectingprepopulatedendpointURLs.WitheachAPIrequest,theconsoledisplaysthedetailedHTTPrequestandresponsedetails.
Facebook’sAccessTokenToolandAccessTokenDebuggerFacebookprovidesanAccessTokenTool,whichissuesaccesstokensthatcanbeusedfortestinganddebugging.Bothuser-basedandapp-basedtokensareissued.Theusertokensissuedbythetoolaresimilartothoseissuedbytheserver-sideWebApplicationfloworclient-sideflow.TheapptokensissuedbythetoolaresimilartothoseissuedbytheClientCredentialsflow.
TheyalsoprovideanAccessTokenDebugger,whichdisplaysinformationaboutOAuthaccesstokens,includingthescopes,validity,issuetime,expirationtimeandmore.
LibrariesManymajorAPIprovidersbuildandmaintainclientlibrariesforaccessingtheirspecificservices.Someoftheselibraries,suchastheGoogleAPIClientsandFacebookSDKsprovidebuilt-insupportforOAuth2.0.WhenOAuthsupportisprovided,theselibrariesoftenabstracttheimplementationsenoughtomakeitreallyeasytoimplement.
HerearesomeAPI-specificclientlibrarieswhichimplementOAuth2.0:
GoogleAPIsClientLibrariesforJava,Objective-C,PHP,Python,Ruby,JavaScript
FacebookSDKsforJavaScript,Android,iOS,PHP
Foursquaredoesnotprovideofficiallibraries,butitlinkstomanycommunity-contributedlibraries,manyofwhichsupportOAuth2.0
SomeoftheselibrariesmakeittriviallyeasytoimplementOAuth2.0.Here’sanexampleusingGoogle’sPythonlibraryonAppEnginewiththelibrary’sdecoratorpattern.ThisexamplerequiresonlyafewlinesofOAuth-specificcode:
from oauth2client.appengine import OAuth2Decorator...decorator = OAuth2Decorator( client_id='CLIENT_ID_FROM_DAILYMOTION', client_secret='CLIENT_SECRET_FROM_DAILYMOTION', scope='read', auth_uri='https://api.dailymotion.com/oauth/authorize', token_uri='https://api.dailymotion.com/oauth/token' )
class MainHandler(webapp.RequestHandler):
@decorator.oauth_required def get(self):
http = decorator.http() resp, content = http.request('https://api.dailymotion.com/me')
path = os.path.join(os.path.dirname(__file__), 'welcome.html') logout = users.create_logout_url('/') variables = { 'content': content, 'logout': logout } self.response.out.write(template.render(path, variables))...
Ifyou’relookingtoimplementOAuth2.0acrossawidevarietyofservices,accessyourownserviceswithOAuthauthorization,ormakerequeststoAPIsprovidedwithoutclientlibraries,youshouldconsiderusinganopensourcelibraryforOAuth2.0.
Sincethespecificationisstillunderactivedevelopment,theselibrarieseachsupportdifferentversionsofthedraftspecification.
Supportingdraft10,severaloftheOAuth2.0implementationsintheGoogleAPIclientlibrariesarealsoavailableasseparatelibraries:
oauth2clientinPython
GoogleOAuthClientLibraryforJava
Additionallibrariesforotherlanguagesareavailableonoauth.net.
GoingFurtherInthisGettingStartedbook,wehavegivenyouanoverviewofhowOAuth2.0worksforobtainingauthorizedaccesstouserdataandwhyitisimportanttoimprovesecurityanduserproductivity.Asanapplicationdeveloper,youshouldnowunderstandthedifferentauthorizationflowsavailableandhowtodecidebetweenthemwhenanAPIprovidersupportsmultipleflows.We’vealsointroducedOpenIDConnect,discussedhowitbuildsontopoftheOAuth2.0protocoltoenableuserauthentication,andsomeofthedifferentsecuritypropertiesofauthenticationversusauthorization.Wehopetheprotocol-levelfoundationprovidedbythisbookwillmakeyouabetterdeveloper,evenifyouendupusinglibrariesthatabstractmanyofthedetails.
AsyouuseOAuth2.0inyourapplication,thereareadditionalconsiderationsyoushouldtakeintoaccounttooptimizeuserexperienceandperformance.Whengettingaccesstoauser’sdata,youshouldexplorehowrequestsfordifferentlevelsofaccessandthetimingofthoserequestsaffectapprovalrates.WhenauthenticatinguserswithOpenIDConnect,youshouldthinkaboutwhichidentityproviderstosupport,howyoudealwithuserswhohaveaccountsonmultipleidentityproviders,howtoimprovesign-inperformancebydecodingtheid_tokenJWT,andotherpotentialfactorsthatcoulddecreasecustomerservicetickets.
WeprimarilyfocusedontheperspectiveofactingasanOAuthclient.ManyapplicationdevelopersmaywishtoopenuptheirdatabybuildingOAuth-authorizedAPIresourceserversandrunningtheirownauthorizationservers.TheknowledgeyougainedfromthisbookshouldhopefullymakeiteasiertounderstandthedetailedspecificationsandsecurityconsiderationsdocumentsthatarereferencedintheAppendixAandareimportantreadingforAPIproviderslaunchingOAuth2.0authorizedservices.
AppendixA.ReferencesWhilethespecificationsformedthebasisforthedescriptionanddiagramsoftheindividualprotocolflows,anumberofotheronlineresourceswereusedinpreparationofthisbook.
SpecificationsOAuth2.0draft
OAuth2.0threatmodelandsecurityconsiderations
OAuth2.0:Bearertokens
OAuth2.0:MACaccessauthentication
OpenIDConnectBasic,StandardandMessages
JSONWebToken(JWT)
OAuth2.0:Tokenrevocation
VendorDocumentationFacebookAuthentication
FacebookGraphAPI
DiggingDeeperintoOAuth2.0onForce.com
AuthenticatingRemoteAccesswithSalesforce
GoogleOAuth2.0
Google’sInternetIdentityResearch
Google’sOAuth2.0ControllersforiOS
OAuth2.0onAndroid
OAuth2.0onAndroidwithGoogleTasks
WindowsLiveSDK—OAuth2.0
MailingListsOAuthIETFWorkingGroup
OpenIDConnectWorkingGroup
Google’soauth2-devforumforquestionsabouttheirOAuth2.0implementation
MiscGoogleCodeblog—OAuth2.0changes
hueniverseblog—OAuth2.0(WithoutSignatures)IsBadfortheWeb
OAuth2.0flowdiagrams
AbouttheAuthorRyanBoydisadeveloperadvocateatGooglefocusedonenablingdeveloperstoextendGoogleAppsandbuildbusinessesontopofGoogletechnology.HepreviouslyworkedonOpenSocialandledthedeveloperrelationsteamforGoogle’sAtomPubAPIs.PriortojoiningGoogle,RyanworkedinhighereducationasawebarchitectforRIT’scentralwebhostingenvironmentandaswebappdeveloperbuildingadmissionsandstudentsystems.
SPECIALOFFER:UpgradethisebookwithO’ReillyUpgradethisebooktodayfor$4.99atoreilly.comandgetaccesstoadditionalDRM-freeformats,includingPDFandEPUB,alongwithfreelifetimeupdates.
Recommended