Authentication

Authorization

Have you ever shared your password with an app so it could use your data?

Yes :-(

Developer opportunity

1) Eliminate the need for users to reveal their password to apps

2) Restrict the level of data available to apps

3) Allow users to revoke access to their data

OAuth 2.0
for Authorization

Do you use the same username & password for multiple web sites?

Yes :-(

How many keystrokes do you type to sign up for a new account?

50+!

Developer opportunity

1) Minimize how many passwords users need

2) Optimize sign-up flows to onboard users faster

OpenID Connect

Agenda

  • Terminology
  • Why do we have OAuth 2.0?
  • Authorization: JS, server-side, mobile
  • Authentication
  • What's this controversy?
  • Resources

Old School: ClientLogin

  1. App asks user for their Google password
  2. App asks Google auth servers for a token to access Calendar (over SSL)
  3. App stores token, sends it to Calendar API
  4. Token expires 2 weeks later; goto 1

Security properties:

  • (+) Stored tokens have limited scope
  • (+) Password only sent over SSL to Google
  • (-) Developers have direct access to password
  • (-) Developers are "encouraged" to store password

Old School: AuthSub

  1. App redirects user to Google asking for a token to access Calendar
  2. User approves and is redirected back to app with token in URL
  3. App exchanges one-time token for long-lived token (over SSL)
  4. App stores long-lived token, sends it to Calendar API

Security properties:

  • (+) Stored tokens have limited scope
  • (+) Password only sent over SSL to Google
  • (+) Developers do not have access to password
  • (+) Users can revoke access to apps
  • (-) Forever-lived tokens often sent in the clear to API

Old School: Secure AuthSub

Don't want to see the warning here?

Then you must:

  • Register your app
  • Use cryptographic signatures on every request!

Old School: OAuth 1.0

Standardized web-based flow like Secure AuthSub

  • Still didn't rely upon SSL/TLS for APIs
  • Painful cryptographic signatures on every request!

New School: OAuth 2.0

Standardized flows

  • Relies upon SSL/TLS for APIs
  • (Mostly) eliminates cryptographic signatures

OAuth 2.0 for Authorization

RFC 6749 is a:
Framework

100+ APIs

Goal

Getting Started

Developer Registration

Pure JavaScript Flow

Developing Client-side Applications

Client-side Flow in JavaScript

Google APIs Client Library for JavaScript

Client-side Flow in JavaScript

Google APIs Client Library for JavaScript

gapi.auth.authorize({
  client_id: '387636757294.apps.googleusercontent.com', 
  scope: 'https://www.googleapis.com/auth/tasks'},
  handleAuthResultPopup);

function handleAuthResultPopup() {
  alert(gapi.auth.getToken());
}

Client-side Flow in JavaScript

Step 1 - App directs the user to Google for Authorization

<script type="text/javascript">
    var clientId = '387636757294.apps.googleusercontent.com';
    var authorizationUrlBase = 'https://accounts.google.com/o/oauth2/auth';
    var redirectUri = 'https://taskmandemo.appspot.com/oauth2callback.html';
    var scope = 'https://www.googleapis.com/auth/tasks';

    function startOauth() {
      var url = authorizationUrlBase;
      url += '?response_type=token'
          +  '&redirect_uri=' + encodeURIComponent(redirectUri)
          +  '&client_id=' + encodeURIComponent(clientId)
          +  '&scope=' + encodeURIComponent(scope);
      var w = window.open(url, 'oauth', 'width=500,height=400');
    }
</script>

Client-side Flow in JavaScript

Step 1 - App directs the user to Google for Authorization

https://accounts.google.com/o/oauth2/auth?
  client_id=387636757294.apps.googleusercontent.com&
  scope=https://www.googleapis.com/auth/tasks&
  redirect_uri=https://taskmandemo.appspot.com/oauth2callback.html&
  response_type=token

Client-side Flow in JavaScript

Step 2a - User authorizes access

Client-side Flow in JavaScript

Step 2b - User is redirected back to the app

https://taskmandemo.appspot.com/oauth2callback.html#
    access_token=ya29.AHES6ZT8XLGWjlrYfP1KvkLQVvYj81C6uA_bUsaZBKWB4ZE&
    token_type=Bearer&
    expires_in=3600

GOAL!

Client-side Flow in JavaScript

Questions!

  • How do I get the token back to the app from the popup window?
  • How do I get another access token?
  • What happens if the user isn't logged in?

Client-side Flow in JavaScript

Summary

  • You're looking for simplicity
  • You like coding in JavaScript
  • You only need access when the user is logged into their account at the API provider

Server-side Flow in Python

Server-side Flow in Python

Step 1 - App re-directs the user


flow = OAuth2WebServerFlow(
    # Visit https://developers.google.com/console to
    # generate your client_id, client_secret and to
    # register your redirect_uri.
    client_id='387636757294.apps.googleusercontent.com',
    client_secret='-8IwOyyundwNY6W0B',
    scope='https://www.googleapis.com/auth/tasks')

callback = self.request.relative_url('/oauth2callback')
authorize_url = flow.step1_get_authorize_url(callback)
self.redirect(authorize_url)
      

Server-side Flow in Python

Step 1 - App re-directs the user

https://accounts.google.com/o/oauth2/auth?
  client_id=387636757294.apps.googleusercontent.com&
  scope=https://www.googleapis.com/auth/tasks&
  redirect_uri=https://taskmandemo.appspot.com/oauth2callback&
  response_type=code&
  access_type=offline

Server-side Flow in Python

Step 2a - User authorizes access

Server-side Flow in Python

Step 2b - User is redirected back to the app

https://taskmandemo.appspot.com/oauth2callback?
    code=4/jHpY6Rslb32PWBiR9bU6wJ4GrMmF.EjOUBPzd

Server-side Flow in Python

Step 3 - App exchanges authorization code for access token

credentials = flow.step2_exchange(self.request.params) 
print 'Access token: %s' % credentials.access_token

GOAL!

print 'Refresh token: %s' % credentials.refresh_token

Server-side Flow in Python

Step 3 - App exchanges authorization code for access token

POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com

client_id=387636757294.apps.googleusercontent.com&
redirect_uri=https://taskmandemo.appspot.com/oauth2callback&
grant_type=authorization_code&
code=4/jHpY6Rslb32PWBiR9bU6wJ4GrMmF.EjOUBPzd&
client_secret=-8IwOyyundwNY6W0B
{ 
  "access_token":"1/fFAGRNJru1FTz70BzhT3Zg",
  "refresh_token":"1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI" 
  "expires_in":3600,
  "token_type":"Bearer",
}

Server-side Flow in Python

Step 4 - App exchanges refresh token for a new access token

# nothing to see here!

Server-side Flow in Python

Step 4 - App exchanges refresh token for a new access token

POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
Content-Type: application/x-www-form-urlencoded

client_id=387636757294.apps.googleusercontent.com&
client_secret=-8IwOyyundwNY6W0B&
refresh_token=1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI&
grant_type=refresh_token
{ 
  "access_token":"1/hGAFZKUio3NOc90BxjU48l",
  "expires_in":3600,
  "token_type":"Bearer"
}

Server-side Flow in Python

Questions!

  • When do refresh tokens expire?
  • How do I store the refresh tokens?

Server-side Flow in Python

Making it even easier: the decorator pattern

decorator = OAuth2Decorator(
  client_id='387636757294.apps.googleusercontent.com'
  client_secret='-8IwOyyundwNY6W0B'
  scope='https://www.googleapis.com/auth/tasks')

http = httplib2.Http(memcache)
service = build("tasks", "v1", http=http)

class MainHandler(webapp.RequestHandler):
  @decorator.oauth_required
  def get(self):
    http = decorator.http()
    tasks = service.tasks.list(tasklist='@default').execute(http)

Server-side Flow in Python

Summary

  • You're looking for long-lived access to user data
  • You need access when the user isn't at the keyboard
  • You need to call the API from server-side code

Other Flows

Other Flows

  • Resource Owner Password Credentials
  • App-based Authorization
    • Client Credentials
    • JWT Assertion

I have the token. Now what?

Calling the API

But... how do I call the API?

Using access tokens

Using a HTTP Header:

GET /tasks/v1/lists/@default/tasks HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer 1/hGAFZKUio3NOc90BxjU48l

Using a Query Parameter:

GET /tasks/v1/lists/@default/tasks?access_token=1/hGAFZKUio3NOc90BxjU48l HTTP/1.1
Host: www.googleapis.com

Tell me more about scopes

Getting authorization for multiple APIs at once

Space-delimited list!

https://www.googleapis.com/auth/tasks https://www.googleapis.com/auth/plus.me

Mobile Authorization

Three Techniques

  • Cross-platform - Embedded WebViews
  • Cross-platform - System web browser
  • Android-specific - GoogleAuthUtil

GoogleAuthUtil

GoogleAuthUtil

App Registration

GoogleAuthUtil

Acquiring an access token

// Allow user to select an account
// AccountManager.getAccountsByType("com.google");

String scope = "https://www.googleapis.com/auth/tasks";

// Get an access token for 'email' account and requested scope
String token = GoogleAuthUtil.getToken(context, email, scope);

GOAL!

OpenID Connect

(OAuth 2.0 for Login)

Authentication Goals

Traditional signup form

Authentication Goals

New signup form

First name:
Last name:
Email:
Profile:

Authentication Goals

  • Make it faster and easier to onboard users
  • Securely get a unique, stable user identifier
  • Personalize your site

Authentication

Step 1 - Use OAuth to get an access token

ScopeDescription
https://www.googleapis.com/auth/userinfo.profileUnique id, name, profile photo, profile URL, country, language, timezone, birthdate, etc.
https://www.googleapis.com/auth/userinfo.emailE-mail address

Request access:

https://accounts.google.com/o/oauth2/auth?
  client_id=387636757294.apps.googleusercontent.com&
  scope=https://www.googleapis.com/auth/userinfo.profile%20https://www.googleapis.com/auth/userinfo.email&
  redirect_uri=https://taskmandemo.appspot.com/oauth2callback-authn.html&
  response_type=token 

Authentication

Step 2 - Use TokenInfo API to get a secure, unique user identifier

My id:

https://www.googleapis.com/oauth2/v1/tokeninfo?
  access_token=
{
 "issued_to": "387636757294.apps.googleusercontent.com",
 "audience": "387636757294.apps.googleusercontent.com",
 "user_id": "113487456102835830811",
 "scope": "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
 "expires_in": 3574,
 "email": "ryan@ryguy.com",
 "verified_email": true,
 "access_type": "online"
}

Personalization

Use UserInfo API to get user profile data

https://www.googleapis.com/oauth2/v1/userinfo?
  access_token=
{
 "id": "113487456102835830811",
 "email": "ryan@ryguy.com",
 "verified_email": true,
 "name": "Ryan Boyd",
 "given_name": "Ryan",
 "family_name": "Boyd",
 "link": "https://plus.google.com/113487456102835830811",
 "picture": "https://lh4.googleusercontent.com/-BET-bMzn99g/AAAAAAAAAAI/AAAAAAAAAQ8/wV0kQ3VUjOE/photo.jpg",
 "gender": "male",
 "birthday": "0000-10-05",
 "locale": "en"
}

Using Google+ Sign-In: Web

Rendering the Button



<script src="http://plus.google.com/js/plusone.js"></script>
<div id="signinButton">
  <span class="g-signin"
    data-scope="https://www.googleapis.com/auth/plus.login"
    data-clientid="387636757294.apps.googleusercontent.com"
    data-redirecturi="postmessage"
    data-accesstype="offline"
    data-cookiepolicy="single_host_origin"
    data-callback="handleAuthResult">
  </span>
</div>
<div id="result"></div>

Using Google+ Sign-In: Web

Handling the Callback

function handleAuthResult(authResult) {
  alert(authResult['access_token']);
}

GOAL!

Using Google+ Sign-In: Mobile

OAuth 2.0 "Controversy"

Some of Eran's Concerns

  • It's only a Framework, not a Specification
  • Bearer Tokens are Bad; Signatures are Important
  • Expiring Tokens are Painful
  • Standards Committees are Rotten

Tools

OAuth 2.0 Playground

developers.google.com/oauthplayground/

OAuth 2.0 Login Demo

oauthssodemo.appspot.com

Resources

<Thank You!>