designing javascript apis
DESCRIPTION
API creation within JavaScript introduces a whole new array of security and request issues that traditional APIs never encounter. In this session we’ll explore several principles behind JavaScript API design and architecture, including OAuth 2 in the JavaScript model, Cross-Origin Resource Sharing for browser security constraints, building action automation with HATEOAS, and challenges behind secure resource consumption through JavaScriptTRANSCRIPT
Designing JavaScript APIs
Jonathan LeBlanc (@jcleblanc)
Global Head of Developer Evangelism at PayPal
API? SDK?
Automation?
What JavaScript Can Feel Like
JavaScript Challenges
The Same-Origin Policy
Keeping Private Keys Private
Not Providing a Hacked Experience
How Did We Used to Do It?
Server-side Proxies
Flash / iFrame Proxies
Private Token Storage
Securing Resources
CORS Easy Access Control
OAuth 2
Tight Access Control
A Modern Approach
OAuth 2 User Agent Flow
Prepare the Redirect URIAuthorization Endpointclient_id response_type (token)scope redirect_uri
Browser RedirectRedirect URI
Redirect the User to Log In
var auth_uri = auth_endpoint + "?response_type=token" + "&client_id=" + client_id + "&scope=profile" + "&redirect_uri=" + window.location; $("#auth_btn").attr("href", auth_uri);
User Agent Flow: Redirect
Extract the Access Token
Fetch the Hash Modaccess_tokenrefresh_tokenexpires_in
Extract Access Token
User Agent Flow: Hash Mod
Extract the Access Token from the Hash
http://site.com/callback#access_token=rBEGu1FQr54AzqE3Q&refresh_token=rEBt51FZr54HayqE3V4a&expires_in=3600
var hash = document.location.hash;var match = hash.match(/access_token=(\w+)/);
Get Privileged API Resources
Set Request Headers + URIResource EndpointHeader: token type + access tokenHeader: accept data type
HTTPS Request
User Agent Flow: Get Resources
Making an Authorized Request
$.ajax({ url: resource_uri, beforeSend: function (xhr) { xhr.setRequestHeader('Authorization', 'OAuth ' + token); xhr.setRequestHeader('Accept', 'application/json'); }, success: function (response) { //use response object }});
CORS Easy Access Control
Access to other domains / subdomains is restricted (same origin policy)
JSONP to request resources across domains
Only supports HTTP GET requests
Cross-origin resource sharing (CORS)Supports additional range of HTTP requests
Cross Origin Issues and Options
Can you use it?
http://caniuse.com/cors
Support: 79.42%Partial support: 8.84%
Total: 88.26%
OPTIONS /v1/oauth2/token HTTP/1.1Origin: http://jcleblanc.comAccess-Control-Request-Method: PUTHost: api.sandbox.paypal.comAccept-Language: en-USConnection: keep-alive...
Site sends Origin header to server
How Does it Work?
Server responds with matching Access-Control-Allow-Origin
header
Access-Control-Allow-Origin: http://jcleblanc.com
Access-Control-Allow-Methods: GET, POST, PUT
Content-Type: text/html; charset=utf-8
How Does it Work?
A Lil’ Bit O’ Automation
Resource Identification
Resources must be manipulated via representations
Self descriptive messages
Hypermedia as the engine of application state
Uniform Interface Sub-Constraints
Resource Identification
Resources must be manipulated via representations
Self descriptive messages
Hypermedia as the engine of application state
Uniform Interface Sub-Constraints
HATEOAS
How we Normally Consume APIs
Using HATEOAS to Automate
curl -v -X GET https://api.sandbox.paypal.com/v1/payments/authorization/2DC87612EK520411B \
-H "Content-Type:application/json" \
-H "Authorization:Bearer ENxom5Fof1KqAffEsXtx1HTEK__KVdIsaCYF8C"
You make an API request
How HATEOAS Works
"links": [ { "href":"https://api.sandbox.paypal.com/v1/payments/ authorization/6H149011U8307001M", "rel":"self", "method":"GET" },{ "href":"https://api.sandbox.paypal.com/v1/payments/ authorization/6H149011U8307001M/capture", "rel":"capture", "method":"POST” },{ "href":"https://api.sandbox.paypal.com/v1/payments/ authorization/6H149011U8307001M/void", "rel":"void", "method":"POST” }]
Open Path Library (what to do next)
Hierarchy of Requests
How do we Make it Work with JS?
Object Chaining
Send complete object to only make 1 request
{ "id": "PAY-17S8410768582940NKEE66EQ", "create_time": "2013-01-31T04:12:02Z", "update_time": "2013-01-31T04:12:04Z", "state": "approved", "intent": "sale", "payer": {...}, "transactions": [{...}], "links": [{...}] }
The System Should be Stateless
Manipulate a concept (e.g. payment) with the intended state
Resources and Representations
var paymentObj = getPreAuth(paymentID) //build pay
object.getNextAction() //next
HATEOAS link.processNext(); //process
action
The first request builds the action objectSubsequent calls manipulate the object
Chaining Actions
Security needs to allow you to work the browser security model
Always assume statelessness
Build to allow your developers to automate complexities
In Summation
Thanks! Questions?http://slideshare.com/jcleblanc
Jonathan LeBlanc (@jcleblanc)
Global Head of Developer Evangelism at PayPal