1 # Copyright 2010 Google Inc.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
17 require 'compat/multi_json'
23 # Manages the persistence of client configuration data and secrets. Format
24 # inspired by the Google API Python client.
26 # @see https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
31 # "client_id": "asdfjasdljfasdkjf",
32 # "client_secret": "1912308409123890",
33 # "redirect_uris": ["https://www.example.com/oauth2callback"],
34 # "auth_uri": "https://accounts.google.com/o/oauth2/auth",
35 # "token_uri": "https://accounts.google.com/o/oauth2/token"
42 # "client_id": "837647042410-75ifg...usercontent.com",
43 # "client_secret":"asdlkfjaskd",
44 # "redirect_uris": ["http://localhost", "urn:ietf:oauth:2.0:oob"],
45 # "auth_uri": "https://accounts.google.com/o/oauth2/auth",
46 # "token_uri": "https://accounts.google.com/o/oauth2/token"
52 # Reads client configuration from a file
54 # @param [String] filename
55 # Path to file to load
57 # @return [Google::APIClient::ClientSecrets]
58 # OAuth client settings
59 def self.load(filename=nil)
60 if filename && File.directory?(filename)
61 search_path = File.expand_path(filename)
65 search_path ||= File.expand_path('.')
66 if File.exist?(File.join(search_path, 'client_secrets.json'))
67 filename = File.join(search_path, 'client_secrets.json')
68 elsif search_path == '/' || search_path =~ /[a-zA-Z]:[\/\\]/
70 'No client_secrets.json filename supplied ' +
71 'and/or could not be found in search path.'
73 search_path = File.expand_path(File.join(search_path, '..'))
76 data = File.open(filename, 'r') { |file| MultiJson.load(file.read) }
81 # Intialize OAuth client settings.
83 # @param [Hash] options
84 # Parsed client secrets files
85 def initialize(options={})
86 # Client auth configuration
87 @flow = options[:flow] || options.keys.first.to_s || 'web'
88 fdata = options[@flow]
89 @client_id = fdata[:client_id] || fdata["client_id"]
90 @client_secret = fdata[:client_secret] || fdata["client_secret"]
91 @redirect_uris = fdata[:redirect_uris] || fdata["redirect_uris"]
92 @redirect_uris ||= [fdata[:redirect_uri]]
93 @javascript_origins = (
94 fdata[:javascript_origins] ||
95 fdata["javascript_origins"]
97 @javascript_origins ||= [fdata[:javascript_origin]]
98 @authorization_uri = fdata[:auth_uri] || fdata["auth_uri"]
99 @authorization_uri ||= fdata[:authorization_uri]
100 @token_credential_uri = fdata[:token_uri] || fdata["token_uri"]
101 @token_credential_uri ||= fdata[:token_credential_uri]
103 # Associated token info
104 @access_token = fdata[:access_token] || fdata["access_token"]
105 @refresh_token = fdata[:refresh_token] || fdata["refresh_token"]
106 @id_token = fdata[:id_token] || fdata["id_token"]
107 @expires_in = fdata[:expires_in] || fdata["expires_in"]
108 @expires_at = fdata[:expires_at] || fdata["expires_at"]
109 @issued_at = fdata[:issued_at] || fdata["issued_at"]
113 :flow, :client_id, :client_secret, :redirect_uris, :javascript_origins,
114 :authorization_uri, :token_credential_uri, :access_token,
115 :refresh_token, :id_token, :expires_in, :expires_at, :issued_at
119 # Serialize back to the original JSON form
124 return MultiJson.dump({
126 'client_id' => self.client_id,
127 'client_secret' => self.client_secret,
128 'redirect_uris' => self.redirect_uris,
129 'javascript_origins' => self.javascript_origins,
130 'auth_uri' => self.authorization_uri,
131 'token_uri' => self.token_credential_uri,
132 'access_token' => self.access_token,
133 'refresh_token' => self.refresh_token,
134 'id_token' => self.id_token,
135 'expires_in' => self.expires_in,
136 'expires_at' => self.expires_at,
137 'issued_at' => self.issued_at
138 }).inject({}) do |accu, (k, v)|
139 # Prunes empty values from JSON output.
140 unless v == nil || (v.respond_to?(:empty?) && v.empty?)
149 gem 'signet', '~> 0.4.0'
150 require 'signet/oauth_2/client'
151 # NOTE: Do not rely on this default value, as it may change
152 new_authorization = Signet::OAuth2::Client.new
153 new_authorization.client_id = self.client_id
154 new_authorization.client_secret = self.client_secret
155 new_authorization.authorization_uri = (
156 self.authorization_uri ||
157 'https://accounts.google.com/o/oauth2/auth'
159 new_authorization.token_credential_uri = (
160 self.token_credential_uri ||
161 'https://accounts.google.com/o/oauth2/token'
163 new_authorization.redirect_uri = self.redirect_uris.first
165 # These are supported, but unlikely.
166 new_authorization.access_token = self.access_token
167 new_authorization.refresh_token = self.refresh_token
168 new_authorization.id_token = self.id_token
169 new_authorization.expires_in = self.expires_in
170 new_authorization.issued_at = self.issued_at if self.issued_at
171 new_authorization.expires_at = self.expires_at if self.expires_at
172 return new_authorization