Class: Google::Auth::UserAuthorizer

Inherits:
Object
  • Object
show all
Defined in:
lib/googleauth/user_authorizer.rb

Overview

Handles an interactive 3-Legged-OAuth2 (3LO) user consent authorization.

Example usage for a simple command line app:

credentials = authorizer.get_credentials(user_id)
if credentials.nil?
  url = authorizer.get_authorization_url(
    base_url: OOB_URI)
  puts "Open the following URL in the browser and enter the " +
       "resulting code after authorization"
  puts url
  code = gets
  credentials = authorizer.get_and_store_credentials_from_code(
    user_id: user_id, code: code, base_url: OOB_URI)
end
# Credentials ready to use, call APIs
...

Direct Known Subclasses

WebUserAuthorizer

Constant Summary collapse

MISMATCHED_CLIENT_ID_ERROR =
"Token client ID of %s does not match configured client id %s".freeze
NIL_CLIENT_ID_ERROR =
"Client id can not be nil.".freeze
NIL_SCOPE_ERROR =
"Scope can not be nil.".freeze
NIL_USER_ID_ERROR =
"User ID can not be nil.".freeze
NIL_TOKEN_STORE_ERROR =
"Can not call method if token store is nil".freeze
MISSING_ABSOLUTE_URL_ERROR =
'Absolute base url required for relative callback url "%s"'.freeze

Instance Method Summary collapse

Constructor Details

#initialize(client_id, scope, token_store, callback_uri = nil) ⇒ UserAuthorizer

Initialize the authorizer

Parameters:

  • client_id (Google::Auth::ClientID)

    Configured ID & secret for this application

  • scope (String, Array<String>)

    Authorization scope to request

  • token_store (Google::Auth::Stores::TokenStore)

    Backing storage for persisting user credentials

  • callback_uri (String) (defaults to: nil)

    URL (either absolute or relative) of the auth callback. Defaults to '/oauth2callback'

Raises:



60
61
62
63
64
65
66
67
68
# File 'lib/googleauth/user_authorizer.rb', line 60

def initialize client_id, scope, token_store, callback_uri = nil
  raise NIL_CLIENT_ID_ERROR if client_id.nil?
  raise NIL_SCOPE_ERROR if scope.nil?

  @client_id = client_id
  @scope = Array(scope)
  @token_store = token_store
  @callback_uri = callback_uri || "/oauth2callback"
end

Instance Method Details

#get_and_store_credentials_from_code(options = {}) ⇒ Google::Auth::UserRefreshCredentials

Exchanges an authorization code returned in the oauth callback. Additionally, stores the resulting credentials in the token store if the exchange is successful.

Parameters:

  • user_id (String)

    Unique ID of the user for loading/storing credentials.

  • code (String)

    The authorization code from the OAuth callback

  • scope (String, Array<String>)

    Authorization scope requested. Overrides the instance scopes if not nil.

  • base_url (String)

    Absolute URL to resolve the configured callback uri against. Required if the configured callback uri is a relative.

Returns:



189
190
191
192
# File 'lib/googleauth/user_authorizer.rb', line 189

def get_and_store_credentials_from_code options = {}
  credentials = get_credentials_from_code options
  store_credentials options[:user_id], credentials
end

#get_authorization_url(options = {}) ⇒ String

Build the URL for requesting authorization.

Parameters:

  • login_hint (String)

    Login hint if need to authorize a specific account. Should be a user's email address or unique profile ID.

  • state (String)

    Opaque state value to be returned to the oauth callback.

  • base_url (String)

    Absolute URL to resolve the configured callback uri against. Required if the configured callback uri is a relative.

  • scope (String, Array<String>)

    Authorization scope to request. Overrides the instance scopes if not nil.

  • additional_parameters (Hash)

    Additional query parameters to be added to the authorization URL.

Returns:

  • (String)

    Authorization url



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/googleauth/user_authorizer.rb', line 87

def get_authorization_url options = {}
  scope = options[:scope] || @scope
  credentials = UserRefreshCredentials.new(
    client_id:     @client_id.id,
    client_secret: @client_id.secret,
    scope:         scope,
    additional_parameters: options[:additional_parameters]
  )
  redirect_uri = redirect_uri_for options[:base_url]
  url = credentials.authorization_uri(access_type:            "offline",
                                      redirect_uri:           redirect_uri,
                                      approval_prompt:        "force",
                                      state:                  options[:state],
                                      include_granted_scopes: true,
                                      login_hint:             options[:login_hint])
  url.to_s
end

#get_credentials(user_id, scope = nil) ⇒ Google::Auth::UserRefreshCredentials

Fetch stored credentials for the user.

Parameters:

  • user_id (String)

    Unique ID of the user for loading/storing credentials.

  • scope (Array<String>, String) (defaults to: nil)

    If specified, only returns credentials that have all the requested scopes

Returns:



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/googleauth/user_authorizer.rb', line 114

def get_credentials user_id, scope = nil
  saved_token = stored_token user_id
  return nil if saved_token.nil?
  data = MultiJson.load saved_token

  if data.fetch("client_id", @client_id.id) != @client_id.id
    raise format(MISMATCHED_CLIENT_ID_ERROR,
                 data["client_id"], @client_id.id)
  end

  credentials = UserRefreshCredentials.new(
    client_id:     @client_id.id,
    client_secret: @client_id.secret,
    scope:         data["scope"] || @scope,
    access_token:  data["access_token"],
    refresh_token: data["refresh_token"],
    expires_at:    data.fetch("expiration_time_millis", 0) / 1000
  )
  scope ||= @scope
  return monitor_credentials user_id, credentials if credentials.includes_scope? scope
  nil
end

#get_credentials_from_code(options = {}) ⇒ Google::Auth::UserRefreshCredentials

Exchanges an authorization code returned in the oauth callback

Parameters:

  • user_id (String)

    Unique ID of the user for loading/storing credentials.

  • code (String)

    The authorization code from the OAuth callback

  • scope (String, Array<String>)

    Authorization scope requested. Overrides the instance scopes if not nil.

  • base_url (String)

    Absolute URL to resolve the configured callback uri against. Required if the configured callback uri is a relative.

  • additional_parameters (Hash)

    Additional parameters to be added to the post body of token endpoint request.

Returns:



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/googleauth/user_authorizer.rb', line 155

def get_credentials_from_code options = {}
  user_id = options[:user_id]
  code = options[:code]
  scope = options[:scope] || @scope
  base_url = options[:base_url]
  credentials = UserRefreshCredentials.new(
    client_id:             @client_id.id,
    client_secret:         @client_id.secret,
    redirect_uri:          redirect_uri_for(base_url),
    scope:                 scope,
    additional_parameters: options[:additional_parameters]
  )
  credentials.code = code
  credentials.fetch_access_token!({})
  monitor_credentials user_id, credentials
end

#revoke_authorization(user_id) ⇒ Object

Revokes a user's credentials. This both revokes the actual grant as well as removes the token from the token store.

Parameters:

  • user_id (String)

    Unique ID of the user for loading/storing credentials.



199
200
201
202
203
204
205
206
207
208
209
# File 'lib/googleauth/user_authorizer.rb', line 199

def revoke_authorization user_id
  credentials = get_credentials user_id
  if credentials
    begin
      @token_store.delete user_id
    ensure
      credentials.revoke!
    end
  end
  nil
end

#store_credentials(user_id, credentials) ⇒ Object

Store credentials for a user. Generally not required to be called directly, but may be used to migrate tokens from one store to another.

Parameters:



219
220
221
222
223
224
225
226
227
228
229
# File 'lib/googleauth/user_authorizer.rb', line 219

def store_credentials user_id, credentials
  json = MultiJson.dump(
    client_id:              credentials.client_id,
    access_token:           credentials.access_token,
    refresh_token:          credentials.refresh_token,
    scope:                  credentials.scope,
    expiration_time_millis: credentials.expires_at.to_i * 1000
  )
  @token_store.store user_id, json
  credentials
end