There are a lot of options here, but everything has sensible defaults.
Check out http://svn.apache.org/viewvc/incubator/shindig/trunk/javascript/samplecontainer/examples/oauth.xml?revision=648154&view=markup
for an example of a simple gadget that uses OAuth.
/**
* Fetches content from the provided URL and feeds that content into the
* callback function.
...
If opt_params[gadgets.io.RequestParameters.AUTHORIZATION] is set
to gadgets.io.AuthorizationType.OAUTH:
This indicates that the container needs to use OAuth to gain access to
the resource specified in the request.
This may require that the gadget obtain the user's content by
directing the user to the service provider to gain access.
The following additional parameters may be specified in opt_params:
gadgets.io.RequestParameters.OAUTH_SERVICE_NAME:
The nickname the gadget uses to refer to the OAuth <Service>
element from it's XML spec. If unspecified, defaults to "".
gadgets.io.RequestParameters.OAUTH_TOKEN_NAME:
The nickname the gadget uses to refer to an oauth token granting
access to a particular resources. If unspecified, defaults to "".
Gadgets can use multiple token names if they have access to
multiple resources from the same service provider. For example, a
gadget with access to a contact list and a calendar might use a token
name of "contacts" to use the contact list token, and a contact list
of "calendar" to use the calendar token.
gadgets.io.RequestParameters.OAUTH_REQUEST_TOKEN
A service provider may be able to automatically provision a
gadget with a request token that is preapproved for access to a
resource. The gadget can use that token with the OAUTH_REQUEST_TOKEN
parameter. If unspecified, defaults to "".
gadgets.io.RequestParamters.OAUTH_REQUEST_TOKEN_SECRET
The secret corresponding to a preapproved request token. If
unspecified, defaults to "".
If OAuth is used, the container should execute the OAuth protocol on
behalf of the gadget. If the gadget has not registered a consumer key
for use with this service provider, the container may choose to use a
well-known public key to sign requests. If the container uses it's
own key, it will include an additional OAuth parameter xoauth_app_url
that identifies the gadget making the request. The container may
include an addititonal OAuth parameter xoauth_app_instance that
identifies an instance of the gadget making the request. If
unspecified, the xoauth_app_instance parameter is assumed to be "".
The makeRequest callback parameter is passed a javascript object with
several fields. If the gadget needs consent from the user to gain
access to the data, the response will include an 'approvalUrl'
attribute. The gadget should direct the user to the approval URL to
approve access. Once the user has approved access, the gadget can
repeat the makeRequest call to retrieve the data.
...
gadgets.io.RequestParameters.OAUTH_REQUEST_TOKEN
A service provider may be able to automatically provision a
gadget with a request token that is preapproved for access to a
resource. The gadget can use that token with the OAUTH_REQUEST_TOKEN
parameter. If unspecified, defaults to "".
gadgets.io.RequestParamters.OAUTH_REQUEST_TOKEN_SECRET
The secret corresponding to a preapproved request token. If
unspecified, defaults to "".
- they are sent to the service provider page, where they can choose to
grant access, deny access, or do nothing.
- at some point the user will signal the gadget (probably by clicking
a button/link) that the data should be available.
(I'm looking into optimizations to skip this step, but something
that works across all service providers will be non-trivial.)
- the gadget will try to fetch the data again.
- at that point the server will find out whether access was permitted or not.
We should probably return an error message to the gadget as one the
response values in the make request callback. How about this:
oauthError: symbolic or numeric error code indicating the reason for
the failure. (It's difficult to define what symbolic constants would
fit here at the moment, we don't know enough about the failure modes.)
oauthErrorText: a textual error message, probably most useful to a
developer debugging their own gadget.
If we do decide that oauthError and oauthErrorText are good ideas,
they will probably need to be free form values until at least
opensocial-0.9.
Cheers,
Brian
well-known public key to sign requests. If the container uses it's
own key, it will include an additional OAuth parameter xoauth_app_url
that identifies the gadget making the request. The container may
include an addititonal OAuth parameter xoauth_app_instance that
identifies an instance of the gadget making the request. If
unspecified, the xoauth_app_instance parameter is assumed to be "".
Doing this without a pop-up is, in theory, possible, but really ugly.
It would always require a full page refresh of the container page.
The OAuth code in Shindig will break for at least two reasons if that
happens, and one of those reasons might be hard to fix depending on
how flexible the service provider is willing to be. I would expect
other implementations to run into the same problems. iframes are a
pain. so are new windows. I don't like top level redirects either.
The popup window seems to be the least evil option, so it should
probably be mentioned in the spec.
You're right, it's useless. Let's not have it. I'll summarize
several proposed changes:
1) OAUTH_REQUEST_TOKEN and OAUTH_REQUEST_TOKEN_SECRET have no default values.
2) xoauth_app_instance shouldn't exist.
3) Additional option gadgets.io.RequestParameters.OAUTH_REQUEST_URL_PARAMS
A service provider may require that a consumer pass additional data on
the request token URL. The gadget can specify the extra data with
OAUTH_REQUEST_URL_PARAMS. If unspecified, defaults to "".
4) Use of a pop-up window to direct the user to the OAuth approval
page is recommended.
parameter. This parameter is optional.
gadgets.io.RequestParamters.OAUTH_REQUEST_TOKEN_SECRET
The secret corresponding to a preapproved request token. This
parameter is optional.
If OAuth is used, the container should execute the OAuth protocol on
behalf of the gadget. If the gadget has not registered a consumer key
for use with this service provider, the container may choose to use a
default RSA signing key corresponding to a well-known certificate to sign
requests. If the container uses a default consumer key, it will include
an additional OAuth parameter xoauth_app_url that identifies the gadget
making the request.
The makeRequest callback parameter is passed a javascript object with
several OAuth specific fields in addition to the normal values returned
by makeRequest:
"oauthApprovalUrl": if this value is specified, the user needs to
visit an external page to approve the gadget's request to access
data. Use of a pop-up window to direct the user to the external
page is recommended. Once the user has approved access, the gadget
can repeate the makeRequest call to retrieve the data.
"oauthError": if this value is specified, it indicates an OAuth
related error occurred. The value will one of a set of string
constants that can be used for programmatically detecting errors.
The constants are undefined for opensocial-0.8, but implementers
should attempt to agree on a set of useful constant values for
standardization in opensocial-0.9.
"oauthErrorText": if this value is specified, it indicates an
OAuth related error occurred. The value is free-form text that
can be used to provide debugging information for gadget developers.
...
It is.
> If so, I
> think the spec needs to be clear that this parameter is not intended
> for use where the authorised request token is published in the gadget
> xml CDATA. It would be a dangerous thing to do so.
It's not dangerous, it's too broken to ever be deployed. Every user
who adds the gadget will end up seeing the same data from the service
provider.
In theory a service provider could host a separate gadget spec for all
of their users, embedding different request tokens in their specs. So
long as the URLs cannot be easily guessed and the request tokens are
short-lived/single use, that is fine from a security standpoint. It's
terrible for scalability, so I don't recommend it. A more scalable
solution is to initialize a gadget with user preferences.
> The code appears to use a pre-defined consumer key and it's own
> private RSA key. So would a better phrasing be "If the gadget has not
> registered a consumer key for use with this service provider, the
> container may choose to use a default consumer key and RSA private
> key." I assume then, that the service provider would verify the
> container by using the container's public key.
Reworded this, have a look at the new wording and let me know what you think.
> Not sure if I have the right end of stick on these points as I haven't
> tested either scenario and not 100% sure. Just wondering if there is
> any test service provider echo code for the RSA scenario?
There's no test service provider out there for this right now, but
there will be soon.
Cheers,
Brian
Doing the XML spec changes and not doing the makeRequest changes
wouldn't make sense.
Cheers,
Brian