[Openid-specs-ab] IDP IFrame Specification
Guibin Kong
guibinkong at google.com
Sun Nov 22 00:04:25 UTC 2015
Attached is the draft for the IDP IFrame specification.
IDP IFrame specification provides a secure, unified and full lifecycle
authorization management API for OAuth 2.0 JavaScript clients. We believe
it can simplify JavaScript app development.
Best regards,
Guibin Kong
William Denniss
Naveen Agarwal
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openid.net/pipermail/openid-specs-ab/attachments/20151121/bf2927b7/attachment.html>
-------------- next part --------------
OAuth Working Group G. Kong
Internet-Draft N. Agarwal
Intended status: Standards Track W. Denniss
Expires: May 24, 2016 Google
November 21, 2015
OAuth 2.0 IDP-IFrame-based Implicit Flow
draft-guibinkong-oauth-idp-iframe-00
Abstract
In this document, we define a new architecture and flow for
JavaScript clients on how to get access tokens and/or ID tokens from
Identity providers (IDP). Instead of getting these tokens from the
IDP Authorization Endpoint (as defined in RFC 6749 [RFC6749] as the
token flow), JavaScript clients now get these tokens from an IFrame
provided by the IDP. This change brings huge performance and
security benefits.
On the performance aspect, the IDP IFrame can transparently cache
these tokens in IDP Web Storage. On page reload or navigation, the
cached tokens may be returned to Relying party (RP) without any
request to IDP. This can avoid the huge traffic to the IDP
authorization endpoint, and improve RP page latency.
On the security aspect, when sending the tokens from IDP domain to RP
domain, HTML5 postMessage is used, instead of the HTTP redirection.
The source origin and target origin of HTML5 postMessage are
trustable, which is not the case for HTTP redirection. This change
mitigates most HTTP redirection related attacks, and makes cross site
request forgery (XSRF) attacks much harder.
This specification also defines a powerful and ready-to-use session
management API for JavaScript clients. 1)The IDP IFrame can
syndicate IDP session state to clients. Clients will get notified
when the user who issued the tokens signs out in the IDP domain, and
when the user signs in again. 2)To work nice with multiLogin IDPs
like Google, the IDP IFrame also provides APIs to enumerate IDP
sessions, to sync session selection across RP domain and sub domains.
3)RP-side logout is also supported, in which case clients stay in
logout/disabled state even after page reload.
Unlike the token flow, which only focuses on permission granting and
token issuing, this specification defines the full life cycle APIs
for JavaScript clients, from permission granting, token issuing,
session management, to permission revocation. Ideally JavaScript
Kong, et al. Expires May 24, 2016 [Page 1]
Internet-Draft oauth_idpiframe November 2015
clients can fulfill all OAuth 2.0 related operations using this
specification.
This specification makes it possible that RP can use one unified
JavaScript client library to access any compliant IDPs. It is hard
to achieve this goal in the past because the session management and
token caching parts were not standardized before.
The architecture and flow defined in this specification should work
fine on any environment that allows IFrame embedding, and supports
Web Storage and postMessage. Based on this assumption, this
specification can be used in normal web and chrome extension context.
Status of This Memo
This Internet-Draft is submitted in full conformance with the
provisions of BCP 78 and BCP 79.
Internet-Drafts are working documents of the Internet Engineering
Task Force (IETF). Note that other groups may also distribute
working documents as Internet-Drafts. The list of current Internet-
Drafts is at http://datatracker.ietf.org/drafts/current/.
Internet-Drafts are draft documents valid for a maximum of six months
and may be updated, replaced, or obsoleted by other documents at any
time. It is inappropriate to use Internet-Drafts as reference
material or to cite them other than as "work in progress."
This Internet-Draft will expire on May 24, 2016.
Copyright Notice
Copyright (c) 2015 IETF Trust and the persons identified as the
document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents
(http://trustee.ietf.org/license-info) in effect on the date of
publication of this document. Please review these documents
carefully, as they describe your rights and restrictions with respect
to this document. Code Components extracted from this document must
include Simplified BSD License text as described in Section 4.e of
the Trust Legal Provisions and are provided without warranty as
described in the Simplified BSD License.
Kong, et al. Expires May 24, 2016 [Page 2]
Internet-Draft oauth_idpiframe November 2015
Table of Contents
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1. Notational Conventions . . . . . . . . . . . . . . . . . 5
1.2. Terminology . . . . . . . . . . . . . . . . . . . . . . . 5
1.3. Architecture Overview . . . . . . . . . . . . . . . . . . 6
1.4. IDP-IFrame-based Implicit Flow . . . . . . . . . . . . . 8
1.5. Login Hint . . . . . . . . . . . . . . . . . . . . . . . 10
1.6. Session Selector . . . . . . . . . . . . . . . . . . . . 11
1.6.1. Default Domain Access Policy . . . . . . . . . . . . 12
1.7. storagerelay Scheme URI . . . . . . . . . . . . . . . . . 12
1.8. Parameters Naming Rules . . . . . . . . . . . . . . . . . 13
2. IDP IFrame . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.1. Embed IDP IFrame Into A Container Page . . . . . . . . . 14
2.1.1. IDP IFrame Initialization Parameters . . . . . . . . 15
2.2. Provisioning . . . . . . . . . . . . . . . . . . . . . . 16
2.3. RPCs . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.3.1. monitorClient . . . . . . . . . . . . . . . . . . . . 17
2.3.2. getSessionSelector . . . . . . . . . . . . . . . . . 18
2.3.3. setSessionSelector . . . . . . . . . . . . . . . . . 20
2.3.4. getTokenResponse . . . . . . . . . . . . . . . . . . 21
2.3.5. listIdpSessions . . . . . . . . . . . . . . . . . . . 23
2.3.6. revoke . . . . . . . . . . . . . . . . . . . . . . . 26
2.4. Events . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.4.1. SessionStateChanged . . . . . . . . . . . . . . . . . 27
2.4.2. SessionSelectorChanged . . . . . . . . . . . . . . . 28
2.4.3. AuthResult . . . . . . . . . . . . . . . . . . . . . 29
3. Authorization Endpoint . . . . . . . . . . . . . . . . . . . 30
3.1. Permission Response Type . . . . . . . . . . . . . . . . 30
3.1.1. Permission Request . . . . . . . . . . . . . . . . . 31
3.1.2. Permission Response . . . . . . . . . . . . . . . . . 32
3.2. storagerelay Scheme URI . . . . . . . . . . . . . . . . . 32
4. Privacy Considerations . . . . . . . . . . . . . . . . . . . 33
5. Security Considerations . . . . . . . . . . . . . . . . . . . 33
6. Normative References . . . . . . . . . . . . . . . . . . . . 34
Appendix A. Acknowledgements . . . . . . . . . . . . . . . . . . 34
Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 34
1. Introduction
The objectives of this specification are to improve security and make
caching of tokens transparent to relying parties. It mitigates the
following concerns related to the token flow defined in the OAuth 2.0
[RFC 6749 [RFC6749]].
1) Security risk caused by HTTP Redirection. Whenever an open-
redirection bug is found in the relying party (RP) domain, it can
be used to relay the access token in the URL fragment to malicious
Kong, et al. Expires May 24, 2016 [Page 3]
Internet-Draft oauth_idpiframe November 2015
URLs controlled by attackers. This has caused several publicly
reported security incidents in the past, and contributed to
negative perceptions of the security of the OAuth 2.0 protocol.
2) Security risk for Cross Site Request Forgery (XSRF). Due to the
inability to verify the origination of the HTTP redirection,
clients must leverage other measures (like the state parameter) to
make sure the response is not forged. This is awkward for pure
JavaScript clients, since additional work is needed to generate a
secure state value and persist it in Web Storage.
3) Performance issues. The token flow doesn't define how to cache
access token for reuse. Serious performance issues may be caused
in both RP side and IDP side, if the client attempts to get a new
access token from the IDP Authorization Endpoint on each page
reload. RP page latency may increase dramatically, and IDP may
need to handle lots of unnecessary traffic.
4) Session Confusion. Clients need to get a new access token when
the old one expires, normally by retrying the token flow in
immediate mode. If IDP session has changed during that period
(and if both sessions have approved the client), the new access
token for another user will be returned silently. Unless
additional measures taken, RP wouldn't notice the session change
in the IDP side, and thus cause session confusion.
5) Popup mode support. For UX reasons, RP may want to open the IDP
authorization page in a popup window. The token flow doesn't
support popup mode directly. RP must setup a callback endpoint to
relay the authorization response to the main window.
6) Work with Multiple Signed-In Sessions. Some IDPs, like Google,
support multiple simultaneously signed-in users (wMultiLogin). RP
needs to remember the active session user selected to avoid
prompting the session selection page to end user on each page
reload. Also, if RP has sub domains, the session selection must
be shared across sub-domains.
7) Security risk caused by token caching in RP side. To fix the
performance issues mentioned above, some RP may maintain a Web-
Storage-based cache in RP domain. This solution may scatter the
security-sensitive tokens across lots of RP domains, some of which
may lack good Web Storage protection. And it is hard to clean the
tokens immediately when user logs out on IDP side.
8) Developer experience issues. The OAuth 2.0 specification
[RFC6749] defines just a framework, which only provides common
solution for part of the problems a developer is facing when using
Kong, et al. Expires May 24, 2016 [Page 4]
Internet-Draft oauth_idpiframe November 2015
OAuth 2.0. IDPs may extend the framework in different way, and
may provide their own client libraries. Developers need to
investigate and include different client libraries for different
IDPs. Sometimes the libraries don't provide full lifecycle
support, for example token revocation API may be missing in some
IDP libraries. Also the libraries may not work well in Chrome
extension context. In short, it is hard to provide a unified
client library that can access all compliant IDPs with full
lifecycle support APIs from both web and chrome extension context.
To mitigate above issues, this specification defines a new
architecture and flow for JavaScript clients, and proposes to replace
and obsolete the OAuth 2.0 token flow described in RFC 6749
[RFC6749].
1.1. Notational Conventions
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
"OPTIONAL" in this document are to be interpreted as described in Key
words for use in RFCs to Indicate Requirement Levels [RFC2119]. If
these words are used without being spelled in uppercase then they are
to be interpreted with their normal natural language meanings.
1.2. Terminology
This specification uses the terms "Access Token", "Authorization
Code", "Authorization Endpoint", "Authorization Grant",
"Authorization Server", "Client", "Client Authentication", "Client
Identifier", "Client Secret", "Grant Type", "Protected Resource",
"Redirection URI", "Refresh Token", "Resource Owner", "Resource
Server", "Response Type", and "Token Endpoint" defined byOAuth 2.0
[RFC6749], the term "User Agent" defined by RFC 2616 [RFC2616].
This specification also defines the following terms:
"Authorization Code Flow" OAuth 2.0 flow in which an Authorization
Code is returned from the Authorization Endpoint and all tokens
are returned from the Token Endpoint.
"Authorization Request" OAuth 2.0 Authorization Request as defined
by [RFC6749].
"Container Page" The page that embeds the IDP IFrame.
"ID Token" JSON Web Token (JWT) [JWT] that contains Claims about the
Authentication event. It MAY contain other Claims.
Kong, et al. Expires May 24, 2016 [Page 5]
Internet-Draft oauth_idpiframe November 2015
"IDP IFrame" IDP IFrame is a hidden IFrame provided by IDP, which
can be embedded into a container page in third party domain, and
provides OAuth 2.0 token and session services on behalf of the IDP
for the JavaScript clients that are running in the container page.
"Login Hint" An opaque string that can uniquely identify a user. It
is used to keep track of the bound user in the RP side in this
specification.
"OpenID Provider (IDP)" OAuth 2.0 Authorization Server that is
capable of Authenticating the End-User and providing Claims to a
Relying Party about the Authentication event and the End-User.
"Personally Identifiable Information (PII)" Information that (a) can
be used to identify the natural person to whom such information
relates, or (b) is or might be directly or indirectly linked to a
natural person to whom such information relates.
"Relying Party (RP)" OAuth 2.0 Client application requiring End-User
Authentication and Claims from an OpenID Provider.
"RP side logout" The RP stays in logout state even if the bound user
has an active session on the IDP side. The logout state means
that RP won't try to get an access token or redirect to IDP
automatically. The RP side logout state should be persistent in
some way, so that it stays in this state after page reload.
"Session Selector" The private storage provided by IDP IFrame for an
RP, to track the session selection and session state. The session
selector may be shared by sub domains decided by the
configuration.
"Storagerelay Scheme URI" A special URI to indicate the
authorization response should be relayed via HTML5 Web Storage.
"Token Flow" OAuth 2.0 flow in which all tokens are returned from
the Authorization Endpoint and neither the Token Endpoint nor an
Authorization Code are used.
1.3. Architecture Overview
This specification defines a new architecture for OAuth 2.0 implicit
flow.
1) IDP must host an IDP IFrame page, which can be embedded into third
party site pages, and receive cross origin message from the
embedding domain via HTML5 postMessage.
Kong, et al. Expires May 24, 2016 [Page 6]
Internet-Draft oauth_idpiframe November 2015
The IDP IFrame can respond to some predefined messages (RPCs);
also it can sends some pre-defined messages (Events) to clients
when some states change in the IDP IFrame.
2) Access tokens MUST be issued from the IDP IFrame. For this
specification, access tokens MUST NOT be returned from
authorization endpoint via HTTP redirection.
The access tokens SHOULD be automatically cached in the IDP IFrame
sessionStorage. The clients always use the same API to get the
token response, and don't need to understand how the cache in the
IDP IFrame operates.
When requesting access tokens, the login hint of the bound user
MUST be included in the request. The access tokens MUST NOT be
returned if the bound user doesn't have an active session in the
IDP side at that time.
3) Login hint is used to keep track of the bound user. The login
hint SHOULD be persistent in the IDP IFrame, in a storage private
to current RP, and MAY be shared by its sub domains. The private
storage provided by IDP IFrame for an RP is called Session
Selector.
The IDP IFrame provides APIs to read and write the data in the
session selector. The RP origin will be checked to decide if an
RP has the permission to operate on a session selector.
If the session selector is changed by a client in one tab, other
clients (no matter in the same or different tabs), will be
notified by a SessionSelectorChanged event. Once receiving that
event, clients should drop the old tokens immediately, and request
tokens for the new bound user.
To support RP side logout, a 'disabled' field is also stored in
the session selector. The SessionSelectorChanged event handler
should also check that field when deciding RP session state.
Session Selector provides a single place to manage the session
selection and session state in a multiple clients, multiple tabs,
and multiple sub domains context, which dramatically decreases the
chance of session confusion.
4) The IDP IFrame will monitor the session state of the bound user in
the IDP site. When the session state changes, a
SessionStateChanged event will be fired to notify the client.
This allows the client in RP domain to syndicate to the IDP
Kong, et al. Expires May 24, 2016 [Page 7]
Internet-Draft oauth_idpiframe November 2015
session state, so as to start to run right after the bound user
logged in; and stop to run right after the bound user logged out.
5) In popup mode, the authorization response in the popup window can
be sent to the IDP IFrame in the main window via web storage
event. Then the IDP IFrame can relay it to the RP by an
AuthResult event. The storagerelay URL scheme is defined to
support this type of communication.
6) To provide full lifecycle API support, clients can also get an
one-time-use code; list IDP sessions; revoke permission via the
IDP IFrame.
1.4. IDP-IFrame-based Implicit Flow
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
| System Browser |
| |
| +----------------------------+ | (4) request +----------+
| | | | permission | |
| | Client App |<-------------------->| Authz |
| | | | | Server |
| +----------------------------+ | | |
| ^ (1) | ^ | | +----------+
| | read | | (3) | |
| | bound | | token | |
| | user | | response | |
| | | | | |
| | (2) | | (5) | |
| | load | | save | |
| | token | | bound | |
| v v | user v |
| +----------------------------+ | +----------+
| | | | (2.1) request | |
| | IDP IFrame | | access token | IDP |
| | |<-------------------->| Server |
| +----------------------------+ | | |
| | +----------+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
Above figure illustrates the interaction of the client app with the
IDP IFrame to get a token response or achieve authorization when
needed. Below are the detailed description for each steps.
1) On RP page loaded, the client SHOULD send getSessionSelector RPC
to read the login hint of the bound user for current RP. If there
is a bound user, go to step 2. Otherwise, go to step 6 to select
one.
Kong, et al. Expires May 24, 2016 [Page 8]
Internet-Draft oauth_idpiframe November 2015
2) The client sends getTokenResponse to load a TokenResponse for the
bound user. The IDP IFrame SHOULD check the sessionStorage-based
cache firstly. If no cached token response found, the IDP IFrame
will connect to IDP server to issue a new one, which SHOULD be
cached for reuse before returning to RP. To check whether a
cached token response is suitable for current request, the
requested client, user, scopes, response types, expires date MUST
be taken into account.
If bound user doesn't have an active session in the IDP side, an
user_logged_out error MUST be returned. If permission from end
user is needed, an immediate_failed error MUST be returned.
It is the client's responsibility to send another getTokenResponse
RPC to renew an expiring access token.
3) If immediate_failed error returns, client SHOULD direct end user
to the authorization endpoint to grant the permission. An
authorization URL should be created whose response_type MUST
contain permission type.
The permission response type, which is defined in this
specification, allows authorization endpoint support both legacy
and new implicit flow at the same time. The information returned
in the response are different. Most obviously, the access token
MUST NOT return in permission response type, whereas the login
hint doesn't be returned for the legacy token response type.
4) After receives a permission request, IDP server shows the approval
page to end user. If user approves the request, the login hint of
the bound user MUST be returned. If user denies the request, an
access_denied error MUST be returned.
In popup mode, a redirect_uri with storagerelay scheme SHOULD be
used. The response will be relayed to the IDP IFrame in the main
window, then it will be sent to target client as an AuthResult
event.
In full page redirection mode, the response SHOULD be sent via
HTTP redirection. Clients MUST read the authorization response
from the URL fragment.
5) On receiving an approval authorization response, the client SHOULD
store the returned login hint into the RP session selector in the
IDP IFrame. The change to the RP session selector will trigger
SessionSelectorChanged events on all tabs in current RP domain,
which will cause the clients on all these tabs reload access
tokens for the new bound user immediately.
Kong, et al. Expires May 24, 2016 [Page 9]
Internet-Draft oauth_idpiframe November 2015
6) There are two ways to switch bound user, or set the initial bound
user: IDP side selection; and RP side selection.
For IDP side selection, end user is directed to IDP Authorization
endpoint with a permission request, then the returned login hint
will be used as the new bound user.
For RP side selection, client first sends a listIdpSessions RPC to
IDP IFrame. The IDP IFrame SHALL enumerate all active IDP
sessions in the response. For sessions that have approved the
client for all the requested scopes, IDP IFrame SHOULD return its
login hint. Then the RP session selection can be switched in RP
side by storing a new login hint into the RP session selector.
7) RP side logout is also supported by the disabled attribute.
Clients MUST NOT automatically get access token or redirect to
select a session if disabled attribute is true.
8) Clients can send revoke RPC to IDP IFrame to revoke all the scopes
granted to current client. Clients MUST have a valid access token
to perform this operation.
9) Clients SHOULD use storagerelay scheme redirect_uri when
requesting a code in popup mode. The response will be relayed to
the IDP IFrame in the main window, then it will be sent to target
client as an AuthResult event.
This allows RP to get authorization code without the need to add
an new endpoint to receive the response.
1.5. Login Hint
Login hint is an opaque string used to keep track of the bound user
in RP side. For better privacy, IDP should use domain-specific login
hint.
Below is the life cycle for a login hint.
1) Login hint is returned in listIdpSessions RPC, or in the
authorization response from IDP authorization endpoint for a
request with permission response type.
2) Client saves it into Session Selector by setSessionSelector RPC.
Other clients will get notified by a SessionSelectorChanged event,
which contains the new login hint.
3) The login hint will be persistent in the web storage of the IDP
IFrame until end user changes it.
Kong, et al. Expires May 24, 2016 [Page 10]
Internet-Draft oauth_idpiframe November 2015
4) On page reload, clients must get bound user firstly from Session
Selector by getSessionSelector RPC.
5) A valid login hint MUST be provided to get tokens by
getTokenResponse RPC. The IDP IFrame will only return tokens for
the user specified by the login hint, and only when the user has
an active session in the IDP side.
1.6. Session Selector
Session selector is a private storage provided by IDP IFrame for an
RP.
SessionSelectorConfig is a data structure that clients use to
designate which session selector should be used.
Different SessionSelectorConfig values will be mapped to different
session selectors, which are totally invisible to each other. For
example, two SessionSelectorConfig with same domain but different
crossSubDomains values will be mapped into two different storage
items, and thus are totally separated session selectors.
Different container pages share the same session selection and
session state only when their SessionSelectorConfig values are
exactly same, in other words, when they designate the same session
selector.
Below is an example of SessionSelectorConfig.
{
"domain":"http://examplerp.com",
"crossSubDomains":true
}
domain
the top RP domain that the bound user to be shared. If
crossSubDomains is false, only clients in the domain can access
the session selector.
crossSubDomains
whether the bound user is shared by sub domains.
policy
(Reserved for future use.) Domain access policy, which controls
whether a subdomain has access to a session selector defined under
parent domain. Current only default policy is defined.
id
Kong, et al. Expires May 24, 2016 [Page 11]
Internet-Draft oauth_idpiframe November 2015
(Reserved for future use.) The ID of the session selector, which
allows an IDP supports multiple session selectors at the same
time. For example, 'test' and 'prod'.
1.6.1. Default Domain Access Policy
Currently only the default policy is defined. For default policy,
below rules apply.
o An https origin can access session selector in http domain. For
example, https://example.com pages can access session selector
defined for domain http://example.com.
o An http origin cannot access session selector in https domain.
For example, http://example.com pages cannot access session
selector defined for domain https://example.com.
o A sub domain in standard port can access parent domain. For
example, http://www.example.com can access http://example.com.
o An origin in non-standard port cannot access an origin with same
hostname but different port number. For example,
http://example.com:8080 and http://example.com are invisible to
each other.
As a result, when crossSubDomains is true:
o if domain is http://example.com, the session selector is visible
to both http://example.com and https://example.com doamins and all
their sub domains in standard ports.
o if domain is https://example.com, the session selector is only
visible to https://example.com domain and all its sub domains in
standard ports.
o if domain http://example.com:8080, the session selector is only
visible to http://example.com:8080 itself. It is not visible to
https://example.com:8080, or http://www.example.com:8080.
Additional policies may be defined in the future to allow more
flexibility.
1.7. storagerelay Scheme URI
HTML5 localStorage can be used to send messages across tabs. If an
item in localStorage is changed by one tab, other tabs will receive a
Storage Event. This feature can be used to relay authorization
response from popup window to the main window.
Kong, et al. Expires May 24, 2016 [Page 12]
Internet-Draft oauth_idpiframe November 2015
Below is the steps to relay authorization response via web storage.
o The IDP IFrame in the main window will listen on storage events.
o The client creates a storagerelay URI, which contains RP origin
and a request ID. Together with the client ID, it will be used to
generate a localStorage key in the authorization endpoint.
o The client creates an auth URL with the stoagerealy URI as the
redirect_uri. Suppose a popup window with the auth URL is opened.
o In the popup window, after an authorization decision is made, the
authorization response is wrapped into a string and written into
localStorage under the key that is generated from the storagerelay
URI. Then the item should be deleted after a small delay. After
that, the popup window can be closed.
o After receiving a storage event, the IDP IFrame will parse the
client ID and origin from the 'key' field. If this is the right
target, the response will be parsed from the 'newValue' field. An
AuthResult event is created to relay the response from the IDP
IFrame to container page. To differentiate the event generated
when deleting the item, storage event with empty 'newValue' will
be ignored.
o Once receiving an AuthResult event, the container page should
check the request ID to make sure the request is originated from
it.
1.8. Parameters Naming Rules
In the essential, this specification defines some data structures
that can be used by JavaScript codes to exchange message across
iframes. Traditionally, JavaScript codes should use camelcase
variable and field names, like clientId, rpcToken, etc.
Unfortunately, RFC 6749 already defines some OAuth 2.0 parameter
names in underbar format, based on the assumption that these
parameters are URL parameters. For example, client_id,
response_type, etc. When communicating with authorization endpoints,
we must use underbar names to be consistent with RFC 6749.
As a result, both camelcase and underbase names are used in this
specification. Below rules apply when deciding which format should
be used.
o The request and response parameter names of the authorization
endpoint must be underbar names (to follow RFC 6749).
Kong, et al. Expires May 24, 2016 [Page 13]
Internet-Draft oauth_idpiframe November 2015
o The params.request of getTokenResponse RPC is used to hold
parameters that are expected to construct the authorization URL.
The parameters inside params.request should be underbar names.
o Some RPC responses are generated by IDP server side endpoints, and
expected to be consumed by clients. It seems insensible to
translate them from underbar names to camelcase names. In this
case, the underbar names are directly exposed to clients. The
examples are the response of getTokenResponse RPC, listIdpSessions
RPC, revoke RPC.
o Same case for the authResult field of AuthResult Event, which
holds authorization response.
o For all other cases, the camelcase names should be used.
2. IDP IFrame
IDP IFrame is a hidden IFrame provided by IDP, which can be embedded
into a container page in third party domain, and provides OAuth 2.0
token and session services on behalf of the IDP for the JavaScript
clients that are running in the container page.
IDP IFrame should only contains HTML and static JavaScript codes.
IDP IFrame JavaScript codes have below dependencies:
HTML5 Web Storage: persist session selector; cache token
responses, etc.
HTML5 postMessage: communicates with container page.
Cookies: Monitor IDP Session state change.
XMLHttpRequest: communicates with IDP server side endpoints (to
issue a token, enumerate session state, etc.).
2.1. Embed IDP IFrame Into A Container Page
IDP IFrame SHOULD NOT set x-frame-options headers.
Since the IDP IFrame will be loaded on each container page reload, it
is vital important to set cache-control: public header to avoid the
huge traffic to load the IDP IFrame itself.
Below is a sample code in a container page to embed an IDP IFrame.
Kong, et al. Expires May 24, 2016 [Page 14]
Internet-Draft oauth_idpiframe November 2015
<iframe id="iframe_id"
style="position: absolute; width: 1px; height: 1px; left: -9999px;"
sandbox="allow-scripts allow-same-origin"
src="https://idp.com/ifr#origin=http://rp.com&rpcToken=8462679">
The iframe has below attributes:
id
Optional. A unique ID for this iframe.
style
CSS code to make the iframe hidden.
sandbox
Enable JavaScript and web storage access.
src
The URL and initialization parameters for the IDP IFrame. Some
initialization parameters can be passed to IDP IFrame in the URL
fragment.
2.1.1. IDP IFrame Initialization Parameters
A container page MUST set initialization parameters for the IDP
IFrame in the URL fragment.
https://idp.com/iframe#origin=https://rp.com&rpcToken=84462679
Below initialization parameters are defined.
origin
Required. The origin of the container page. This is the only
origin that the IDP IFrame will receive message from and send
message to.
rpcToken
Required. A random secret is shared between the IDP IFrame and
the container page. For each message between them, the RPC token
must be included.
clearCache
Optional. A boolean value (0 or 1) to indicate whether to clear
the cache for current origin in the IDP IFrame. If clearCache=1
included, when initializing the IDP IFrame, all cached data for
current origin will be cleared.
Kong, et al. Expires May 24, 2016 [Page 15]
Internet-Draft oauth_idpiframe November 2015
2.2. Provisioning
The communication between the container page and the IDP IFrame is
based on HTML5 postMessage. The message handler on the receiving
side should be ready before the sending side can send out a message.
Below rules are defined for this.
1) The container page MUST make its message handler ready before
embedding the IDP IFrame.
2) Once loaded, the IDP IFrame MUST get the client origin and RPC
token from the URL fragment, and make its message handler ready.
For security reasons, only that client origin is allowed to
communicate with the IDP IFrame loaded.
3) The IDP IFrame MUST send an idpReady event to the client origin.
4) Only after the idpReady event is received can the container page
send messages to the IDP IFrame.
Below is an example idpReady event from the IDP IFrame.
{
"method":"fireIdpEvent",
"params":{"type":"idpReady"},
"rpcToken":"12345678"
}
Below initialization parameters are defined.
method
The message type. For all IDP events, the method is
'fireIdpEvent'.
params.type
The event type.
rpcToken
Shared RPC token.
2.3. RPCs
After the IDP IFrame provisioning, the container page can send RPC
requests to IDP IFrame, for example, to get an OAuth 2.0 access
token, to list all IDP sessions, etc.
Kong, et al. Expires May 24, 2016 [Page 16]
Internet-Draft oauth_idpiframe November 2015
On receiving a request, the IDP IFrame MUST first check its validity,
then process it by looking up the cache or sending AJAX requests to
server side endpoints. If there is an id field in the RPC request,
the IDP IFrame MUST send back a RPC response.
The RPC requests and responses will be serialized to strings, and
sent via HTML5 postMessage.
IDP IFrame MUST support below RPCs.
monitorClient
Registers a client to the IDP IFrame, so that IDP IFrame knows
that the target client is running on the container page.
getSessionSelector
Gets the persistent login hint of bound user and the disabled
state in the session selector of current RP.
setSessionSelector
Changes the bound user or the disabled state in the session
selector of current RP.
getTokenResponse
Loads access token or ID token from the IDP IFrame. The tokens
MAY be loaded from the cache in the IDP IFrame.
listIdpSessions
Lists all IDP sessions. The response MAY be loaded from the cache
in the IDP IFrame.
revoke
Revokes all granted permissions for the client.
2.3.1. monitorClient
Registers a client to the IDP IFrame, so that IDP IFrame knows that
the target client is running on the container page. The container
page can receive IDP IFrame Events for a client only after the client
is registered.
Below is an example monitorClient RPC request.
Kong, et al. Expires May 24, 2016 [Page 17]
Internet-Draft oauth_idpiframe November 2015
{
"method":"monitorClient",
"params":{
"clientId":"483367325260.googleusercontent.com"
},
"id":"205-335666.4125872184",
"rpcToken":"12345678"
}
method
The RPC type.
params.clientId
The ID of the client to be registered.
id
Optional. The ID of the request. If present, the IDP IFrame must
return a response as defined below.
rpcToken
Shared RPC token.
Below is an example monitorClient RPC response.
{
"id":"205-335666.4125872184",
"result":true,
"rpcToken":"12345678"
}
result
A boolean value to indicate whether the client is registered or
not.
id
The ID of the corresponding RPC request.
rpcToken
Shared RPC token.
2.3.2. getSessionSelector
Gets the persistent login hint of bound user and the disabled state
in the session selector of current RP.
Below is an example getSessionSelector RPC request.
Kong, et al. Expires May 24, 2016 [Page 18]
Internet-Draft oauth_idpiframe November 2015
{
"method":"getSessionSelector",
"params":{
"crossSubDomains":true,
"domain":"https://gapi-idp.appspot.com"
},
"id":"505-382131.15223600523",
"rpcToken":"12345678"
}
method
The RPC type.
params.crossSubDomains
Session selector config field 'crossSubDomains'.
params.domain
Session selector config field 'domain'.
id
Optional. The ID of the request. If present, the IDP IFrame must
return a response as defined below.
rpcToken
Shared RPC Token.
Below is an example getSessionSelector RPC response.
{
"id":"505-382131.15223600523",
"result":{
"hint":"AJMrCA...",
"disabled":false
},
"rpcToken":"12345678"
}
Below is an example getSessionSelector RPC response.
result.hint
The login hint of the bound user.
result.disabled
A boolean value to indicate whether user is RP side logged out.
Value true means logged out.
id
The ID of the corresponding RPC request.
Kong, et al. Expires May 24, 2016 [Page 19]
Internet-Draft oauth_idpiframe November 2015
rpcToken
Shared RPC Token.
2.3.3. setSessionSelector
Changes the bound user or the disabled state in the session selector
of current RP.
Below is an example setSessionSelector RPC request.
{
"method":"setSessionSelector",
"params":
"crossSubDomains":true,
"domain":"https://gapi-idp.appspot.com",
"hint":"AJMrCA...",
"disabled":false
},
"id":"163-974071.9209347457",
"rpcToken":"12345678"
}
method
The RPC type.
params.crossSubDomains
Session selector config field 'crossSubDomains'.
params.domain
Session selector config field 'domain'.
params.hint
The login hint of the bound user to be set.
params.disabled
A boolean value to indicate whether user is RP side logged out.
Value true means logged-out.
id
Optional. The ID of the request. If present, the IDP IFrame must
return a response as defined below.
rpcToken
Shared RPC Token.
Below is an example setSessionSelector RPC response.
Kong, et al. Expires May 24, 2016 [Page 20]
Internet-Draft oauth_idpiframe November 2015
{
"id":"163-974071.9209347457",
"result":true,
"rpcToken":"12345678"
}
result
A boolean value to indicate whether the session selector is
updated successfully.
id
The ID of the corresponding RPC request.
rpcToken
Shared RPC Token.
2.3.4. getTokenResponse
Loads access token or ID token from the IDP IFrame. The tokens may
be loaded from the cache in the IDP IFrame.
Below is an example getTokenResponse RPC request.
{
"method":"getTokenResponse",
"params":{
"clientId":"48336732526.apps.googleusercontent.com",
"loginHint":"AJMrCA...",
"sessionSelector":{
"domain":"http://examplerp.com"
},
"request":{
"response_type":"token id_token",
"scope":"profile email"
},
"forceRefresh":false
},
"id":"205-791673.6432735061",
"rpcToken":"12345678"
}
method
The RPC type.
params.clientId
The ID of the client.
params.loginHint
Kong, et al. Expires May 24, 2016 [Page 21]
Internet-Draft oauth_idpiframe November 2015
The login hint of the bound user.
params.sessionSelector.domain
The RP session selector domain, which should be used when
generating domain specific login hint.
params.request.response_type
OAuth 2.0 request parameter response_type. Valid values are
'token', 'id_token', or 'token id_token'.
params.request.scope
OAuth 2.0 request parameter scope.
params.forceRefresh
Whether to ignore the cache, and get a new token response from IDP
server.
id
Optional. The ID of the request. If present, the IDP IFrame must
return a response as defined below.
rpcToken
Shared RPC Token.
Below is an example getTokenResponse RPC response.
{
"id":"205-791673.6432735061",
"result":{
"token_type":"Bearer",
"access_token":"ya29.9A...",
"scope":"openid email",
"login_hint":"AJMrCA...",
"id_token":"eUxA....",
"session_state":{
"extraQueryParams":{
"authuser":"0"
}
},
"first_issued_at":1420598000330,
"expires_at":1420601600330
"expires_in":3600,
},
"rpcToken":"12345678"
}
result.token_type
OAuth 2.0 response parameter token_type.
Kong, et al. Expires May 24, 2016 [Page 22]
Internet-Draft oauth_idpiframe November 2015
result.access_token
OAuth 2.0 response parameter access_token. This parameter is
always returned.
result.id_token
OpenID connect response parameter id_token. Returned only when
'id_token' is requested.
params.login_hint
The login hint of the user who issues the tokens.
params.scope
The granted scopes for the tokens. This may return different
value to the requested scope due to two reasons:
1) IDP may turn the scope alias into a normalized form.
2) To support incremental auth, IDP may include previously granted
scopes.
params.session_state
The session selection information for current session. Can be
used to select the session in the IDP.
params.session_state.extraQueryParams
Extra query parameters used to select the user session in IDP
side. The parameters inside extraQueryParams (say, authuser) are
IDP specific. The client doesn't need to know the meaning of
them. When generating authorization URL, these parameters will be
appended to the URL query.
id
The ID of the corresponding RPC request.
rpcToken
Shared RPC Token.
2.3.5. listIdpSessions
Enumerates all IDP sessions. The response may be loaded from the
cache in the IDP IFrame.
If a session user has already approved all requested scopes, the
login hint will be included in the response.
If a session user has already approved email-related scope, the IDP
is RECOMMENDED to return the email of the session user.
Kong, et al. Expires May 24, 2016 [Page 23]
Internet-Draft oauth_idpiframe November 2015
If a session user has already approved profile-related scope, the IDP
is RECOMMENDED to return the displayName and photoUrl of the session
user.
The email, displayName, and photoUrl allow RP to render a user
friendly session selection UI on the RP side.
Below is an example listIdpSessions RPC request.
{
"method":"listIdpSessions",
"params":{
"clientId":"4833673.apps.googleusercontent.com",
"sessionSelector":{
"domain":"http://examplerp.com"
},
"request":{
"scope":"profile email"
},
"forceRefresh":false
},
"id":"599-211931.20572639475"
"rpcToken":"12345678"
}
method
The RPC type.
params.clientId
The ID of the client to be registered.
params.sessionSelector.domain
The RP session selector domain, which should be used when
generating domain specific login hint.
params.request.scope
The OAuth 2.0 request parameter scope.
params.forceRefresh
Whether to ignore the cache, and refresh the session states from
IDP server.
id
Optional. The ID of the request. If present, the IDP IFrame must
return a response as defined below.
rpcToken
Shared RPC Token.
Kong, et al. Expires May 24, 2016 [Page 24]
Internet-Draft oauth_idpiframe November 2015
Below is an example listIdpSessions RPC response.
{
"id":"599-211931.20572639475",
"result":{
"sessions":[{
"login_hint":"AJMrCA...",
"email":"test at gmail.com",
"displayName":"James Zhao",
"photoUrl":"https://someUrl",
"session_state":{
"extraQueryParams":{"authuser":"0"}
}
},{
"session_state":{
"extraQueryParams":{"authuser":"1"}
}
}],
"first_issued_at":1420605596916,
"expires_at":1420609196916,
"scope":"openid email"
},
"rpcToken":"12345678"
}
result.sessions
An array of session meta information. Each element corresponds to
one IDP session.
result.sessions[i].login_hint
The login hint of the session user. Returned only when the
session user has granted all requested scopes for the client.
result.sessions[i].email
The email of the session user. Returned only when the session
user has granted email-related scope for the client.
result.sessions[i].displayName
The login hint of the session user. Returned only when the
session user has granted profile-related for the client.
result.sessions[i].photoUrl
The login hint of the session user. Returned only when the
session user has granted profile-related for the client.
result.sessions[i].session_state
session selection information. Can be used to select the session
in the IDP.
Kong, et al. Expires May 24, 2016 [Page 25]
Internet-Draft oauth_idpiframe November 2015
params.sessions[i].session_state.extraQueryParams
Extra query parameters used to select the user session in IDP
side. The parameters inside extraQueryParams (say, authuser) are
IDP specific. The client doesn't need to know the meaning of
them. When generating authorization URL, these parameters will be
appended to the URL query.
id
The ID of the corresponding RPC request.
rpcToken
Shared RPC Token.
2.3.6. revoke
Revokes all granted permissions for the client.
Below is an example revoke RPC request.
{
"method":"revoke",
"params":{
"clientId":"4833673.apps.googleusercontent.com"
"token":"ya29.9A...",
},
"id":"993-345439.5964317359"
"rpcToken":"12345678"
}
method
The RPC type.
params.clientId
The ID of the client to be registered.
params.token
The access token for the client.
id
Optional. The ID of the request. If present, the IDP IFrame must
return a response as defined below.
rpcToken
Shared RPC Token.
Below is an example revoke RPC response.
Kong, et al. Expires May 24, 2016 [Page 26]
Internet-Draft oauth_idpiframe November 2015
{
"id":"993-345439.5964317359",
"result":true,
"rpcToken":"12345678"
}
result
A boolean value to indicate whether the revocation is successful.
id
The ID of the corresponding RPC request.
rpcToken
Shared RPC Token.
2.4. Events
When something changes in the IDP IFrame, the IDP IFrame can fire
Events to notify the client.
IDP IFrame will fire below events.
SessionStateChanged
The IDP session state has changed.
SessionSelectorChange
The session selection or RP logout state has changed.
AuthResult
An authorization response is returned.
2.4.1. SessionStateChanged
The IDP IFrame will monitor the IDP session cookie. If it changes,
the IDP IFrame will connect IDP server to refresh the session state.
If the login state for the bound user changes, a SessionStateChanged
event will be fired to notify the client in the container page.
Below is an example SessionStateChanged event.
Kong, et al. Expires May 24, 2016 [Page 27]
Internet-Draft oauth_idpiframe November 2015
{
"method":"fireIdpEvent",
"params":{
"type":"sessionStateChanged",
"clientId":"685319905637.apps.googleusercontent.com",
"user":"AOu8..."
"sessionState":{
"extraQueryParams":{"authuser":"0"}
}
},
"rpcToken":"12345678"
}
method
The message type. For all IDP events, the method is
'fireIdpEvent'.
params.type
The event type.
params.clientId
The ID of the client to be notified.
params.user
The login hint of the bound user.
params.sessionState
The session selection information. If this field is missing, it
means the user is logged out.
rpcToken
Shared RPC token.
2.4.2. SessionSelectorChanged
If the Session Selector value for current RP is changed by one
client, the SessionSelectorChanged event will be fired to notify all
clients to update.
There are two types of changes.
o Bound user changed.
o RP side logout state (disabled state) changed.
Below is an example SessionSelectorChanged event.
Kong, et al. Expires May 24, 2016 [Page 28]
Internet-Draft oauth_idpiframe November 2015
{
"method":"fireIdpEvent",
"params":{
"type":"sessionSelectorChanged",
"newValue":{
"hint":"AOEu8...",
"disabled":false
},
"domain":"https://fi-idpiframe-app.appspot.com",
"crossSubDomains":true
},
"rpcToken":"12345678"
}
method
The message type. For all IDP events, the method is
'fireIdpEvent'.
params.type
The event type.
params.newValue.hint
The login hint of the bound user.
params.newValue.disabled
The RP side logout state. If user is logged out in the RP side,
'disabled' should be true.
params.domain
Session selector config field 'domain'.
params.crossSubDomains
Session selector config field 'crossSubDomains'.
rpcToken
Shared RPC token.
2.4.3. AuthResult
In popup mode, after an authorization decision is made on the IDP
consent page in the popup window, the container page in the main
window will receive an AuthResult event, which holds the
authorization response.
Below is an example AuthResult event.
Kong, et al. Expires May 24, 2016 [Page 29]
Internet-Draft oauth_idpiframe November 2015
{
"method":"fireIdpEvent",
"params":{
"type":"authResult",
"clientId":"685319905637.apps.googleusercontent.com",
"id":"auth273261",
"authResult":{
"login_hint":"AOHg..."
}
},
"rpcToken":"12345678"
}
method
The message type. For all IDP events, the method is
'fireIdpEvent'.
params.type
The event type.
params.clientId
The target client ID.
params.id
The request ID.
params.authResult
The authorization response.
rpcToken
Shared RPC token.
3. Authorization Endpoint
To support the IDP IFrame based Implicit Flow, IDP need to make some
changes to Authorization Endpoint.
o Support permission response type.
o Support storagerelay scheme URI.
3.1. Permission Response Type
The permission response type, instead of the token response type,
should be used in the authorization URL to request approval from end
user for the IDP IFrame based implicit flow.
Below are the differences between them.
Kong, et al. Expires May 24, 2016 [Page 30]
Internet-Draft oauth_idpiframe November 2015
o Access tokens will be returned for token response type, but not
for permission response type.
o Login hint for the approving user will be returned for permission
response type, but not for token response type.
o Client ID is also returned for permission response type, which
makes it easy for a RP to use a shared endpoint to handle the
redirection from multiples IDPs or for different clients.
The permission response type is used in below two scenarios.
o Request permissions. Presents consent page to end user to grant
(additional) permissions to the client.
o Switch bound user. Allows end user to select a different session,
thus changes the bound user.
The code and id_token response types can be used together with
permission response type. This allows the JavaScript clients to
piggy-back authorization code and ID token for its server side when
requesting permissions from authorization endpoint.
To make it clear, although the authorization code is returned from
the IDP IFrame in an AuthResult event, it is issued in authorization
endpoint (instead of the IDP IFrame server side endpoint).
3.1.1. Permission Request
The client constructs the request URI by adding the following
parameters to the query component of the authorization endpoint URI.
response_type
REQUIRED. Value must have "permission".
client_id
REQUIRED. The client identifier as described in Section 2.2 of
RFC 6749.
redirect_uri
OPTIONAL. As described in Section 3.1.2 of RFC 6749. Or a
storagerelay URI as described in Section 3.2 below.
scope
OPTIONAL. The scope of the access request as described by
Section 3.3 of RFC 6749.
state
Kong, et al. Expires May 24, 2016 [Page 31]
Internet-Draft oauth_idpiframe November 2015
OPTIONAL. An opaque value used by the client to maintain state
between the request and callback. The authorization server
includes this value when directing the user-agent back to the
client.
3.1.2. Permission Response
After an authorization decision is made on the authorization
endpoint, an authorization response is created and sent back to the
client that initiates the request.
If the redirect_uri is a storagerelay URI, the client will receive an
AuthResult event as defined in section 2.4.3, which holds the
authorization response in the authResult field.
If the redirect_uri is not a storagerelay URI, the authorization
response will be encoded into the fragment component of the
redirection URI.
If end user approve the request, following parameters will be
included in the response.
login_hint
REQUIRED. The hint of the session that approved the request.
client_id
REQUIRED. The client identifier returned to support multiple
clients in single relying parties page.
state
REQUIRED if the "state" parameter was present in the client
authorization request. The exact value received from the client.
If end user deny the request, or if there is some error which causes
the failure to approve the request, an error response will be
generated. See section 4.2.2.1 of RFC 6749 for the format of an
error response.
3.2. storagerelay Scheme URI
IDP MUST support storagerelay scheme URI to allow authorization
response to be transferred via HTML5 Web Storage in popup mode.
Below is the format of the storagerelay URI.
storagerelay://scheme/host?id={requestId}
scheme
Kong, et al. Expires May 24, 2016 [Page 32]
Internet-Draft oauth_idpiframe November 2015
The scheme of the RP origin. For example, http, https, or chrome-
extension.
host
The host part of the RP origin. for example, example.com,
example.com:8888.
id
An id for the request to differentiate the requests for different
tabs for the same client.
Below is an example storagerelay URI.
storagerelay://https/rp.com?id=auth304970
4. Privacy Considerations
Essentially, login hint has similar meaning as the ID token subject,
which is defined in OpenID connect specification. No additional
privacy issue should be incurred by the use of login hint in this
specification.
To protect the End-User from a possible correlation among clients,
domain specific login hint SHOULD be used.
5. Security Considerations
Below are some general rules for postMessage, which MUST be followed
by both IDP and RP implementers.
1) Always verify the sender's identity using the origin and possibly
source properties.
Any window (including, for example, http://evil.example.com) can
send a message to any other window, and you have no guarantees
that an unknown sender will not send malicious messages.
For IDP IFrame, the source property MUST be the iframe's direct
parent. The origin property MUST be literally same as the value
of origin initialization parameter as defined in section 2.1.1.
2) Always verify the syntax of the received message.
Otherwise, a security hole in the site you trusted to send only
trusted messages could then open a cross-site scripting hole in
your site.
Kong, et al. Expires May 24, 2016 [Page 33]
Internet-Draft oauth_idpiframe November 2015
3) Always specify an exact target origin, not *, when you use
postMessage to send data to other windows.
A malicious site can change the location of the window without
your knowledge, and therefore it can intercept the data sent using
postMessage.
6. Normative References
[RFC6749] Hardt, D., Ed., "The OAuth 2.0 Authorization Framework",
RFC 6749, DOI 10.17487/RFC6749, October 2012,
<http://www.rfc-editor.org/info/rfc6749>.
[RFC6819] Lodderstedt, T., Ed., McGloin, M., and P. Hunt, "OAuth 2.0
Threat Model and Security Considerations", RFC 6819,
DOI 10.17487/RFC6819, January 2013,
<http://www.rfc-editor.org/info/rfc6819>.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997,
<http://www.rfc-editor.org/info/rfc2119>.
Appendix A. Acknowledgements
The following individuals contributed ideas, feedback, and wording
that shaped and formed the final specification:
Breno de Medeiros, John Hjelmstad, and Ben Wiley Sittler.
Authors' Addresses
Guibin Kong
Google
1600 Amphitheatre Pkwy
Mountain View, CA 94043
USA
Phone: +1 650-253-0000
Email: guibinkong at google.com
URI: http://google.com/
Kong, et al. Expires May 24, 2016 [Page 34]
Internet-Draft oauth_idpiframe November 2015
Naveen Agarwal
Google
1600 Amphitheatre Pkwy
Mountain View, CA 94043
USA
Phone: +1 650-253-0000
Email: naa at google.com
URI: http://google.com/
William Denniss
Google
1600 Amphitheatre Pkwy
Mountain View, CA 94043
USA
Phone: +1 650-253-0000
Email: wdenniss at google.com
URI: http://google.com/
Kong, et al. Expires May 24, 2016 [Page 35]
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openid.net/pipermail/openid-specs-ab/attachments/20151121/bf2927b7/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: IdpIFrame.xml
Type: text/xml
Size: 79902 bytes
Desc: not available
URL: <http://lists.openid.net/pipermail/openid-specs-ab/attachments/20151121/bf2927b7/attachment.xml>
More information about the Openid-specs-ab
mailing list