diff options
48 files changed, 4852 insertions, 8 deletions
diff --git a/doc/specs/draft-hardt-oauth-01.htm b/doc/specs/draft-hardt-oauth-01.htm new file mode 100644 index 0000000..e13cdf0 --- /dev/null +++ b/doc/specs/draft-hardt-oauth-01.htm @@ -0,0 +1,2313 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<!-- saved from url=(0137)https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor34 --> +<HTML><HEAD><META http-equiv="Content-Type" content="text/html; charset=UTF-8"></HEAD><BODY> + + + + + + + +<DIV> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<TABLE summary="layout" width="66%" border="0" cellpadding="0" cellspacing="0"><TBODY><TR><TD><TABLE summary="layout" width="100%" border="0" cellpadding="2" cellspacing="1"> +<TBODY><TR><TD>Internet Engineering Task Force</TD><TD>D. Hardt, Ed.</TD></TR> +<TR><TD>Internet-Draft</TD><TD>Microsoft</TD></TR> +<TR><TD>Intended status: Informational</TD><TD>A. Tom</TD></TR> +<TR><TD>Expires: July 19, 2010</TD><TD>Yahoo!</TD></TR> +<TR><TD> </TD><TD>B. Eaton</TD></TR> +<TR><TD> </TD><TD>Google</TD></TR> +<TR><TD> </TD><TD>Y. Goland</TD></TR> +<TR><TD> </TD><TD>Microsoft</TD></TR> +<TR><TD> </TD><TD>January 15, 2010</TD></TR> +</TBODY></TABLE></TD></TR></TBODY></TABLE> +<H1><BR>OAuth Web Resource Authorization + Profiles<BR>draft-hardt-oauth-01</H1> + +<H3>Abstract</H3> + +<P>The OAuth Web Resource Authorization Profiles (OAuth WRAP) allow a + server hosting a Protected Resource to delegate authorization to one or + more authorities. An application (Client) accesses the Protected + Resource by presenting a short lived, opaque, bearer token (Access + Token) obtained from an authority (Authorization Server). There are + Profiles for how a Client may obtain an Access Token when acting + autonomously or on behalf of a User. +</P> +<H3>Status of this Memo</H3> +<P> +This Internet-Draft is submitted to IETF in full +conformance with the provisions of BCP 78 and BCP 79.</P> +<P> +Internet-Drafts are working documents of the Internet Engineering +Task Force (IETF), its areas, and its working groups. +Note that other groups may also distribute working documents as +Internet-Drafts.</P> +<P> +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.”</P> +<P> +The list of current Internet-Drafts can be accessed at +<A href="http://www.ietf.org/ietf/1id-abstracts.txt" target="_blank">http://www.ietf.org/ietf/1id-<WBR>abstracts.txt</A>.</P> +<P> +The list of Internet-Draft Shadow Directories can be accessed at +<A href="http://www.ietf.org/shadow.html" target="_blank">http://www.ietf.org/shadow.<WBR>html</A>.</P> +<P> +This Internet-Draft will expire on July 19, 2010.</P> + +<H3>Copyright Notice</H3> +<P> +Copyright (c) 2010 IETF Trust and the persons identified as the +document authors. All rights reserved.</P> +<P> +This document is subject to BCP 78 and the IETF Trust's Legal +Provisions Relating to IETF Documents in effect on the date of +publication of this document (<A href="http://trustee.ietf.org/license-info" target="_blank">http://trustee.ietf.org/<WBR>license-info</A>). +Please review these documents carefully, as they describe your +rights and restrictions with respect to this document.</P> +<A name="0.2_toc"></A><BR><HR> +<H3>Table of Contents</H3> +<P> +<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor1">1.</A> +Overview<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor2">1.1.</A> +Accessing a Protected Resource<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor3">1.2.</A> +Autonomous Client Profiles<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor4">1.3.</A> +User Delegation Profiles<BR> +<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor5">2.</A> +Requirements Language<BR> +<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor6">3.</A> +Definitions<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor7">3.1.</A> +URLs<BR> +<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_ProtectedResource">4.</A> +Accessing a Protected Resource<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor8">4.1.</A> +Access Token<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor9">4.2.</A> +Acquiring an Access Token<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor10">4.3.</A> +Client Calls Protected Resource Using HTTP Header<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor11">4.4.</A> +Client Calls Protected Resource Using URL Query Parameter<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor12">4.5.</A> +Client Calls Protected Resource Using Post Parameter<BR> +<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_autonomous.profiles">5.</A> +Acquiring an Access Token: Autonomous Client Profiles<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p1">5.1.</A> +Client Account and Password Profile<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor13">5.1.1.</A> +Provisioning<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p1request">5.1.2.</A> +Client Requests Access Token<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor14">5.1.3.</A> +Successful Access Token Response from Authorization Server<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor15">5.1.4.</A> +Unsuccessful Access Token Response from Authorization Server<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor16">5.1.5.</A> +Client Refreshes Access Token<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p2">5.2.</A> +Assertion Profile<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor17">5.2.1.</A> +Provisioning<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p2.assertion">5.2.2.</A> +Client Obtains Assertion<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p2.request">5.2.3.</A> +Client Requests Access Token<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor18">5.2.4.</A> +Successful Access Token Response from Authorization Server<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor19">5.2.5.</A> +Unsuccessful Access Token Response from Authorization Server<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor20">5.2.6.</A> +Client Refreshes Access Token<BR> +<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_user.profiles">6.</A> +Acquiring an Access Token: User Delegation Profiles<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p3">6.1.</A> +Username and Password Profile<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor21">6.1.1.</A> +Provisioning<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p3.password">6.1.2.</A> +Client Obtains Username and Password<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p3.request">6.1.3.</A> +Client Requests Access Token<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor22">6.1.4.</A> +Successful Access Token Response from Authorization Server<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor23">6.1.5.</A> +Unsuccessful Access Token Response from Authorization Server<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor24">6.1.6.</A> +Verification URL Response from Authorization Server<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor25">6.1.7.</A> +CAPTCHA Response from Authorization Server<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor26">6.1.8.</A> +Client Refreshes Access Token<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor27">6.1.9.</A> +Successful Access Token Refresh<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor28">6.1.10.</A> +Unsuccessful Access Token Refresh<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p4">6.2.</A> +Web App Profile<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor29">6.2.1.</A> +Provisioning<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p4.authorization">6.2.2.</A> +Client Directs the User to the Authorization Server<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor30">6.2.3.</A> +Authorization Server Confirms Authorization Request with User<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor31">6.2.4.</A> +Authorization Server Directs User back to the Client<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p4.request">6.2.5.</A> +Client Requests Access Token<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor32">6.2.6.</A> +Successful Access Token Response from Authorization Server<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor33">6.2.7.</A> +Unsuccessful Access Token Response from Authorization Server<BR> + <A href="./draft-hardt-oauth-01_files/draft-hardt-oauth-01.htm">6.2.8.</A> +Client Refreshes Access Token<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor35">6.2.9.</A> +Successful Access Token Refresh<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor36">6.2.10.</A> +Unsuccessful Access Token Refresh<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p5">6.3.</A> +Rich App Profile<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor37">6.3.1.</A> +Provisioning<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p5.authorization">6.3.2.</A> +Client Directs the User to the Authorization Server<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor38">6.3.3.</A> +Authorization Server Confirms Authorization Request with User<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p5.request">6.3.4.</A> +Client Requests Access Token<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p5.verification">6.3.5.</A> +Successful Access Token Response from Authorization Server<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor41">6.3.6.</A> +Unsuccessful Access Token Response from Authorization Server<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor42">6.3.7.</A> +Client Refreshes Access Token<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor43">6.3.8.</A> +Successful Access Token Refresh<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor44">6.3.9.</A> +Unsuccessful Access Token Refresh<BR> +<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_ParamCon">7.</A> +Parameter Considerations<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor45">7.1.</A> +Authorization Server Request / Response Parameter Encoding<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor46">7.2.</A> +Parameter Size<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor47">7.3.</A> +Access Token Format<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor48">7.4.</A> +Refresh Token Format<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor49">7.5.</A> +Additional Authorization Server Parameters<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor50">7.6.</A> +Parameter Names and Order<BR> +<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_IANA">8.</A> +IANA Considerations<BR> +<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_Security">9.</A> +Security Considerations<BR> +<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_rfc.references1">10.</A> +References<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_rfc.references1">10.1.</A> +Normative References<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_rfc.references2">10.2.</A> +Informative References<BR> +<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor53">Appendix A.</A> +Client Account and Password Profile Example<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor54">A.1.</A> +Provisioning<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor55">A.2.</A> +Client Requests Access Token<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor56">A.3.</A> +Successful Access Token Response from Authorization Server<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor57">A.4.</A> +Client Calls Protected Resource<BR> +<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor58">Appendix B.</A> +Web App Profile Example<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor59">B.1.</A> +Provisioning<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor60">B.2.</A> +Client Directs the User to the Server<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor61">B.3.</A> +Authorization Server Confirms Delegation Request with User<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor62">B.4.</A> +Server Directs User back to the Client<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor63">B.5.</A> +Client Requests Access Token<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor64">B.6.</A> +Successful Access Token Response from Authorization Server<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor65">B.7.</A> +Client Calls Protected Resource<BR> + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_anchor66">B.8.</A> +Client Refreshes Access Token<BR> +<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_rfc.authors">§</A> +Authors' Addresses<BR> +</P> +<BR clear="all"> + +<A name="0.2_anchor1"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.1"></A><H3>1. +Overview</H3> + +<P>As the internet has evolved, there is a growing trend for a variety + of applications (Clients) to access resources through an API over HTTP + or other protocols. Often these resources require authorization for + access and are Protected Resources. The systems that are trusted to make + authorization decisions may be independent from the Protected Resources + for scale and security reasons. The OAuth Web Resource Authorization + Profiles (OAuth WRAP) enable a Protected Resource to delegate the + authorization to access a Protected Resource to one or more trusted + authorities. +</P> +<P>Clients that wish to access a Protected Resource first obtain + authorization from a trusted authority (Authorization Server). Different + credentials and profiles can be used to obtain this authorization, but + once authorized, the Client is provided an Access Token, and possible a + Refresh Token to obtain new Access Tokens. The Authorization Server + typically includes authorization information in the Access Token and + digitally signs the Access Token. Protected Resource can verify that an + Access Token received from a Client was issued by a trusted + Authorization Server and is valid. The Protected Resource can then + examine the contents of the Access Token to determine the authorization + that has been granted to the Client. +</P> +<A name="0.2_anchor2"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.1.1"></A><H3>1.1. +Accessing a Protected Resource</H3> + +<P>The Access Token is opaque to the Client, and can be any format + agreed to between the Authorization Server and the Protected Resource + enabling existing systems to reuse suitable tokens, or use a standard + token format such as a Simple Web Token or JSON Web Token. Since the + Access Token provides the Client authorization to the Protected + Resource for the life of the Access Token, the Authorization Server + should issue Access Tokens that expire within an appropriate time. + When an Access Token expires, the Client requests a new Access Token + from the Authorization Server, which once again computes the Client's + authorization, and issues a new Access Token. <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_fig1">Figure 1</A> below shows the flow between the Client and + Authorization Server (A,B); and then between the Client and Protected + Resource (C,D): +</P><BR><HR> +<A name="0.2_fig1"></A> +<DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> +---+ +---------------+ + | C |--(A)------ credentials --------->| Authorization | + | l |<-(B)------ Access Token ---------| Server | + | i | +---------------+ + | e | + | n | Access Token +-----------+ + | t |--(C)----- in HTTP header ------->| Protected | + | |<-(D)------ API response ---------| Resource | + +---+ +-----------+ +</PRE></DIV><TABLE border="0" cellpadding="0" cellspacing="2" align="center"><TBODY><TR><TD align="center"><FONT face="monaco, MS Sans Serif" size="1"><B> Figure 1 </B></FONT><BR></TD></TR></TBODY></TABLE><HR> + +<P>In step A, the Client presents credentials to the Authorization + Server in exchange for an Access Token. +</P> +<P> A Profile specifies the credentials to be provided in step A, and + how the Client obtains them. This specification defines a number of + Profiles; additional Profiles may be defined to support additional + scenarios. The Profiles in this specification are separated into two + groups: autonomous profiles where the Client as acting for itself, and + user delegation profiles where the Client is acting on behalf of a + User. +</P> +<A name="0.2_anchor3"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.1.2"></A><H3>1.2. +Autonomous Client Profiles</H3> + +<P>The following two Profiles (see <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_autonomous.profiles">Section 5<SPAN> (</SPAN><SPAN>Acquiring an Access Token: Autonomous Client Profiles</SPAN><SPAN>)</SPAN></A>) are recommended for scenarios + involving a Client acting autonomously. +</P> +<P>Client Account and Password Profile (<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p1">Section 5.1<SPAN> (</SPAN><SPAN>Client Account and Password Profile</SPAN><SPAN>)</SPAN></A>): This + is the simplest Profile. The Client is provisioned with an account name + and corresponding password by the Authorization Server. The Client + presents the account name and password to the Access Token URL at the + Authorization Server in exchange for an Access Token. This Profile is + not intended for a Client acting on behalf of a User. See the User + Delegation Profiles. +</P> +<P>Assertion Profile (<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p2">Section 5.2<SPAN> (</SPAN><SPAN>Assertion Profile</SPAN><SPAN>)</SPAN></A>): This profile enables a + Client with a <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_OASIS.saml-core-2.0-os">SAML<SPAN> (</SPAN><SPAN>Cantor, S., Kemp, J., Philpott, R., and E. Maler, “Assertions and Protocol for the OASIS Security Assertion Markup Language (SAML) V2.0,” March 2005.</SPAN><SPAN>)</SPAN></A> [OASIS.saml‑core‑2.0‑os] or other + assertion recognized by the Authorization Server. The Client presents + the assertion to the Access Token URL at the Authorization Server in + exchange for an Access Token. How the Client obtains the assertion is + out of scope of OAuth WRAP. +</P> +<P>Access Tokens are short lived bearer tokens. When the Protected + Resource is presented with an expired Access Token by the Client, the + Protected Resource returns an error. The Client presents the assertion + once again to the Authorization Server to obtain a new Access + Token. +</P> +<A name="0.2_anchor4"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.1.3"></A><H3>1.3. +User Delegation Profiles</H3> + +<P>Common scenarios involve the User delegating to a Client to act on + the User's behalf, adding another party (the User) to the protocol. In + these Profiles (see <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_user.profiles">Section 6<SPAN> (</SPAN><SPAN>Acquiring an Access Token: User Delegation Profiles</SPAN><SPAN>)</SPAN></A>), the Client + receives a Refresh Token when it acquires the first Access Token. When + an Access Token expires, the Client presents the Refresh Token to + acquire a new Access Token. Refresh Tokens are sensitive as they + represent long-lived permissions to access a Protected Resource and + are always transmitted using HTTPS. +</P> +<P>Username and Password Profile (<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p3">Section 6.1<SPAN> (</SPAN><SPAN>Username and Password Profile</SPAN><SPAN>)</SPAN></A>): While + the User may use a username and password to authenticate to the + Authorization Server, it is undesirable for the Client to store the + User's username and password. In this profile the User provides their + username and password to an application (Client) they have installed + on their device. The Client presents a Client Identifier, the username + and password (credentials) to the Access Token URL at the + Authorization Server in exchange for an Access Token and a Refresh + Token as depicted in <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_fig2">Figure 2</A> below. +</P><BR><HR> +<A name="0.2_fig2"></A> +<DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> +---+ +---------------+ + | C |--(A)------ credentials --------->| Authorization | + | l |<-(B)------ Access Token ---------| Server | + | i | Refresh Token +---------------+ + | e | + | n | Access Token +-----------+ + | t |--(C)----- in HTTP header ------->| Protected | + | |<-(D)------ API response ---------| Resource | + +---+ +-----------+ + +</PRE></DIV><TABLE border="0" cellpadding="0" cellspacing="2" align="center"><TBODY><TR><TD align="center"><FONT face="monaco, MS Sans Serif" size="1"><B> Figure 2 </B></FONT><BR></TD></TR></TBODY></TABLE><HR> + +<P>When the Access Token expires, the Client presents the Refresh + Token to the Refresh Token URL at the Authorization Server in exchange + for a new Access Token (<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_fig3">Figure 3</A>, steps A and B). + The Client then uses the new Access Token to access the Protected + Resource (<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_fig3">Figure 3</A>, steps C and D). +</P><BR><HR> +<A name="0.2_fig3"></A> +<DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> +---+ +---------------+ + | C |--(A)----- Refresh Token -------->| Authorization | + | l |<-(B)------ Access Token ---------| Server | + | i | +---------------+ + | e | + | n | Access Token +-----------+ + | t |--(C)----- in HTTP header ------->| Protected | + | |<-(D)------ API response ---------| Resource | + +---+ +-----------+ + +</PRE></DIV><TABLE border="0" cellpadding="0" cellspacing="2" align="center"><TBODY><TR><TD align="center"><FONT face="monaco, MS Sans Serif" size="1"><B> Figure 3 </B></FONT><BR></TD></TR></TBODY></TABLE><HR> + +<P>Web App Profile (<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p4">Section 6.2<SPAN> (</SPAN><SPAN>Web App Profile</SPAN><SPAN>)</SPAN></A>): It is undesirable for + a User to provide their Authorization Server username and password to + web applications. Additionally, the User may authenticate to the + Authorization Server using other mechanisms than a username and + password. In this profile, a web application (Client) has been + provisioned with a Client Identifier and Client Secret and may have + registered a Callback URL. <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_fig4">Figure 4</A> below + illustrates the protocol. (A) The Client initiates the protocol by + redirecting the User to the User Authorization URL at the + Authorization Server passing the Client Identifier and the Callback + URL. (B) The Authorization Server authenticates the User, confirms the + User would like to authorize the Client to access the Protected + Resource, and generates a Verification Code. (C) The Authorization + Server then redirects the User to the Callback URL at the Client + passing along the Verification Code. +</P><BR><HR> +<A name="0.2_fig4"></A> +<DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> +---------+ + | Web App | + | Client | + +---------+ + v ^ + | | + (A) (C) + | | + \ \ + +---------+ +---------------+ + | |\---(C)-- Verification Code ----<| | + | User | | Authorization | + | at |<---(B)-- User authenticates --->| Server | + | Browser | | | + | |\---(A)-- Client Identifier ---->| | + +---------+ +---------------+ +</PRE></DIV><TABLE border="0" cellpadding="0" cellspacing="2" align="center"><TBODY><TR><TD align="center"><FONT face="monaco, MS Sans Serif" size="1"><B> Figure 4 </B></FONT><BR></TD></TR></TBODY></TABLE><HR> + +<P>Similar to step A in <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_fig2">Figure 2</A>, the Client then + presents the Client Identifier, Client Secret, Callback URL and + Verification code (credentials) to the Access Token URL at the + Authorization Server for an Access Token and a Refresh Token. +</P> +<P>Rich App Profile (<A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p5">Section 6.3<SPAN> (</SPAN><SPAN>Rich App Profile</SPAN><SPAN>)</SPAN></A>): This profile is + suitable when the Client is an application the User has installed on + their device and a web browser is available, but it is undesirable for + the User to provide their username and password to an application, or + the user may not be using a username and password to authenticate to + the Authorization Server. +</P> +<P>The Client initiates the protocol by directing the User's browser + to the Authorization URL at the Authorization Server passing the + Client Identifier and potentially a Callback URL. The Authorization + Server authenticates the User, confirms the User would like to + authorize the Client to access the Protected Resource, and generates a + Verification Code. The Verification Code may be communicated back to + the Client in a number of ways: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>a.</DT> +<DD>the Authorization Server presents the Verification Code to the + User, who is instructed to enter the Verification Code directly in + the Client; +</DD> +<DT>b.</DT> +<DD>the Client reads the Verification Code from the title of the + web page presented by the Authorization Server; +</DD> +<DT>c.</DT> +<DD>the Authorization Server redirects the User to the Callback URL + that presents Client specific language for the User to enter the + Verification Code into the Client; or +</DD> +<DT>d.</DT> +<DD>the Client has registered a custom scheme and the Authorization + Server redirects the browser to the custom scheme that causes the + User's browser to load the Client application with the + Verification Code as a parameter. +</DD> +</DL></BLOCKQUOTE> + +<P>Similar to step A in <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_fig2">Figure 2</A>, the Client then + presents the Client Identifier, Callback URL (if provided) and + Verification code (credentials) to the Access Token URL at the + Authorization Server for an Access Token and a Refresh Token. +</P> +<A name="0.2_anchor5"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.2"></A><H3>2. +Requirements Language</H3> + +<P>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_RFC2119">[RFC2119]<SPAN> (</SPAN><SPAN>Bradner, S., “Key words for use in RFCs to Indicate Requirement Levels,” March 1997.</SPAN><SPAN>)</SPAN></A>. Domain name examples use <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_RFC2606">[RFC2606]<SPAN> (</SPAN><SPAN>Eastlake, D. and A. Panitz, “Reserved Top Level DNS Names,” June 1999.</SPAN><SPAN>)</SPAN></A>. +</P> +<A name="0.2_anchor6"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.3"></A><H3>3. +Definitions</H3> + +<P></P> +<BLOCKQUOTE><DL> +<DT>Access Token:</DT> +<DD>a short lived bearer token issued by the + Authorization Server to the Client. The Access Token is presented by + the Client to the Protected Resource to access protected + resources. +</DD> +<DT>Authorization Server:</DT> +<DD>an authorization resource that + issues Access Tokens to Clients after successful authorization. May + be the same entity as the Protected Resource. +</DD> +<DT>Client:</DT> +<DD>an application that would like access to a + Protected Resource. Client Identifier:"> a value used by a Client + to identify itself to the Authorization Server. This may be a human + readable string or an opaque identifier. +</DD> +<DT>Client Secret:</DT> +<DD>a secret used by a web application + Client to establish ownership of the Client Identifier. +</DD> +<DT>Profile:</DT> +<DD>a mechanism for a Client to obtain an Access + Token from an Authorization Server. +</DD> +<DT>Protected Resource:</DT> +<DD>a protected API that allows access + via OAuth WRAP. May be the same entity as the Authorization Server. + Refresh Token:"> a long lived bearer token used by a Client to + acquire an Access Token from an Authorization Server. +</DD> +<DT>User:</DT> +<DD>an individual who has an account with the + Authorization Server. +</DD> +<DT>Verification Code:</DT> +<DD>a code used by a Client to verify + the User has authorized the Client to have specific access to a + Protected Resource. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_anchor7"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.3.1"></A><H3>3.1. +URLs</H3> + +<P></P> +<BLOCKQUOTE><DL> +<DT>Access Token URL:</DT> +<DD>the Authorization Server URL at + which an Access Token is requested by the Client. The URL may + accept a variety of parameters depending on the Profile. A Refresh + Token may also be returned to the Client. This URL MUST be an + HTTPS URL and MUST always be called with POST. +</DD> +<DT>Callback URL:</DT> +<DD>the Client URL where the User will be + redirected after an authorization request to the Authorization + Server. +</DD> +<DT>Refresh Token URL:</DT> +<DD>the Authorization Server URL at + which a Refresh Token is presented in exchange for a new Access + Token is requested. This URL MUST be an HTTPS URL and MUST always + be called with POST. +</DD> +<DT>User Authorization URL:</DT> +<DD>the Authorization Server URL + where the Client redirects the User to make an authorization + request. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_ProtectedResource"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.4"></A><H3>4. +Accessing a Protected Resource</H3> + +<P>Clients always present an Access Token to access a Protected + Resource. Use of the Authorization header is RECOMMENDED, since HTTP + implementations are aware that Authorization headers have special + security properties and may require special treatment in caches and + logs. Protected Resources SHOULD take precautions to insure that Access + Tokens are not inadvertently logged or captured. In addition to the + methods presented here, the Protected Resource MAY allow the Client to + present the Access Token using any scheme agreed on by the Client and + Protected Resource. +</P> +<A name="0.2_anchor8"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.4.1"></A><H3>4.1. +Access Token</H3> + +<P>The exact format of the Access Token is opaque to Clients and is + out of scope of this specification. However, Protected Resources MUST + be able to verify that the Access Token was issued by a trusted + Authorization Server and is still valid. Access Tokens SHOULD + periodically expire. The expiry time of Access Tokens is determined as + an appropriate balance between excessive resource utilization if too + short and unauthorized access if too long. +</P> +<A name="0.2_anchor9"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.4.2"></A><H3>4.2. +Acquiring an Access Token</H3> + +<P>An Authorization Server may support one or more protocol profiles + that enable a Client to obtain an Access Token that can be used to + access a Protected Resource. +</P> +<P>Client developers only need to implement the profile(s) that align + with how their application will be deployed and are supported by the + Authorization Server. +</P> +<P>Authorization Server developers only need to implement the + profile(s) that are appropriate for them. +</P> +<P>Protected Resource developers do not implement a profile as the + Client always interacts with the Protected Resource by presenting an + Access Token. +</P> +<P><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_ParamCon">Section 7<SPAN> (</SPAN><SPAN>Parameter Considerations</SPAN><SPAN>)</SPAN></A> has general information about + parameters passed to and from the Authorization Server. +</P> +<P>See <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_autonomous.profiles">Section 5<SPAN> (</SPAN><SPAN>Acquiring an Access Token: Autonomous Client Profiles</SPAN><SPAN>)</SPAN></A> for how the Client + acquires an Access Token when acting autonomously, and <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_user.profiles">Section 6<SPAN> (</SPAN><SPAN>Acquiring an Access Token: User Delegation Profiles</SPAN><SPAN>)</SPAN></A> for how the Client acquires an Access + Token when acting acting on behalf of a User. +</P> +<A name="0.2_anchor10"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.4.3"></A><H3>4.3. +Client Calls Protected Resource Using HTTP Header</H3> + +<P>The Protected Resource SHOULD enable Clients to access the + Protected Resource by including the Access Token in the HTTP + Authorization header using the OAuth WRAP scheme with the following + parameter: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>access_token</DT> +<DD> REQUIRED. The value of the + Access Token +</DD> +</DL></BLOCKQUOTE> + +<P>For example, if the Access Token is the string 123456789, the HTTP + header would be: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> Authorization: WRAP access_token="123456789" +</PRE></DIV> +<P>Note that per section 1.2 of <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_RFC2617">[RFC2617]<SPAN> (</SPAN><SPAN>Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S., Leach, P., Luotonen, A., and L. Stewart, “HTTP Authentication: Basic and Digest Access Authentication,” June 1999.</SPAN><SPAN>)</SPAN></A> that + the following header is also valid: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> Authorization: WRAP access_token = 123456789 +</PRE></DIV> +<P>If the Access Token has expired or is invalid, the Protected + Resource MUST return: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 401 Unauthorized +</PRE></DIV> +<P>and the HTTP header: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> WWW-Authenticate: WRAP +</PRE></DIV> +<A name="0.2_anchor11"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.4.4"></A><H3>4.4. +Client Calls Protected Resource Using URL Query Parameter</H3> + +<P>The Protected Resource MAY allow the Client to access protected + resources at the Protected Resource by including the following HTTP + URL query parameter in the URL: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>access_token</DT> +<DD> REQUIRED. The value of the + Access Token +</DD> +</DL></BLOCKQUOTE> + +<P>If the Access Token has expired or is invalid, the Protected + Resource MUST return: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 401 Unauthorized +</PRE></DIV> +<P>and the HTTP header: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> WWW-Authenticate: WRAP +</PRE></DIV> +<A name="0.2_anchor12"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.4.5"></A><H3>4.5. +Client Calls Protected Resource Using Post Parameter</H3> + +<P>The Protected Resource MAY allow the Client to access protected + resources at the Protected Resource by including the following + parameter in the body of a HTTP post message formatted as + application/x-www-form-<WBR>urlencoded per <A href="http://www.w3.org/TR/1999/REC-W3C.REC-html40-19980424-19991224/interact/forms.html#h-17.13.4.1" target="_blank">17.13.4</A> + of <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_W3C.REC-html40-19980424">HTML 4.01<SPAN> (</SPAN><SPAN>Hors, A., Jacobs, I., and D. Raggett, “HTML 4.0 Specification,” April 1998.</SPAN><SPAN>)</SPAN></A> [W3C.REC‑html40‑19980424]: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>access_token</DT> +<DD> REQUIRED. The value of the + Access Token +</DD> +</DL></BLOCKQUOTE> + +<P>If the Access Token has expired or is invalid, the Protected + Resource MUST return: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 401 Unauthorized +</PRE></DIV> +<P>and the HTTP header: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> WWW-Authenticate: WRAP +</PRE></DIV> +<A name="0.2_autonomous.profiles"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.5"></A><H3>5. +Acquiring an Access Token: Autonomous Client Profiles</H3> + +<P>These are the profiles the Client uses when acting autonomously. +</P> +<A name="0.2_p1"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.5.1"></A><H3>5.1. +Client Account and Password Profile</H3> + +<P>This profile is suitable when the Client is an application calling + the Protected Resource on behalf of an organization and the + Authorization Server accepts account passwords for authentication. + This enables the Authorization Server to use an existing + authentication mechanism. This profile SHOULD NOT be used when the + Client is acting on behalf of a user. Profiles <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p3">6.1<SPAN> (</SPAN><SPAN>Username and Password Profile</SPAN><SPAN>)</SPAN></A>, <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p4">6.2<SPAN> (</SPAN><SPAN>Web App Profile</SPAN><SPAN>)</SPAN></A> or + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p5">6.3<SPAN> (</SPAN><SPAN>Rich App Profile</SPAN><SPAN>)</SPAN></A> are RECOMMENDED when a + Client is acting on behalf of a User. +</P> +<A name="0.2_anchor13"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.5.1.1"></A><H3>5.1.1. +Provisioning</H3> + +<P>Prior to initiating this protocol profile, the Client MUST have + obtained an account name and account password from the Authorization + Server. +</P> +<A name="0.2_p1request"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.5.1.2"></A><H3>5.1.2. +Client Requests Access Token</H3> + +<P>The Client makes an HTTPS request to the Authorization Server's + Access Token URL using POST. The request contains the following + parameters: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_name</DT> +<DD> REQUIRED. The account + name. +</DD> +<DT>wrap_password</DT> +<DD> REQUIRED. The account + password. +</DD> +<DT>wrap_scope</DT> +<DD> OPTIONAL. The Authorization + Server MAY define authorization scope values for the Client to + include. +</DD> +<DT>Additional parameters</DT> +<DD>Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_anchor14"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.5.1.3"></A><H3>5.1.3. +Successful Access Token Response from Authorization Server</H3> + +<P>If successful, the Authorization Server returns: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 200 OK +</PRE></DIV> +<P>with the Refresh Token and an Access Token in the response body. + The response body contains the following parameters: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_refresh_token</DT> +<DD> REQUIRED. The + Refresh Token. +</DD> +<DT>wrap_access_token</DT> +<DD> REQUIRED. The Access + Token. +</DD> +<DT>wrap_access_token_expires_in</DT> +<DD> OPTIONAL. + The lifetime of the Access Token in seconds. For example, 3600 + represents one hour. +</DD> +<DT>Additional parameters</DT> +<DD> Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<P>The Client may now use the Access Token to access the Protected + Resource per <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_ProtectedResource">Section 4<SPAN> (</SPAN><SPAN>Accessing a Protected Resource</SPAN><SPAN>)</SPAN></A> +</P> +<A name="0.2_anchor15"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.5.1.4"></A><H3>5.1.4. +Unsuccessful Access Token Response from Authorization Server</H3> + +<P>If the Client account name and password are invalid, the + Authorization Server MUST respond with: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 401 Unauthorized +</PRE></DIV> +<P>and the HTTP header: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> WWW-Authenticate: WRAP +</PRE></DIV> +<P>The Client MUST obtain a valid account name and password before + retrying the request. +</P> +<A name="0.2_anchor16"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.5.1.5"></A><H3>5.1.5. +Client Refreshes Access Token</H3> + +<P>Authorization Servers SHOULD issue Access Tokens that expire and + require Clients to refresh them. Upon receiving the HTTP 401 + response when accessing protected resources per <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_ProtectedResource">Section 4<SPAN> (</SPAN><SPAN>Accessing a Protected Resource</SPAN><SPAN>)</SPAN></A>, the Client should request a new + Access Token by repeating <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p1request">Section 5.1.2<SPAN> (</SPAN><SPAN>Client Requests Access Token</SPAN><SPAN>)</SPAN></A> +</P> +<A name="0.2_p2"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.5.2"></A><H3>5.2. +Assertion Profile</H3> + +<A name="0.2_anchor17"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.5.2.1"></A><H3>5.2.1. +Provisioning</H3> + +<P>Prior to initiating this protocol profile, the Client MUST have a + mechanism for obtained an assertion from an assertion issuer that + can be presented to the Authorization Server for access to the + Protected Resource. +</P> +<A name="0.2_p2.assertion"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.5.2.2"></A><H3>5.2.2. +Client Obtains Assertion</H3> + +<P>The Client obtains an assertion. The process for obtaining the + assertion is defined by the assertion issuer and the Authorization + Server, and is out of scope of this specification. +</P> +<A name="0.2_p2.request"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.5.2.3"></A><H3>5.2.3. +Client Requests Access Token</H3> + +<P>The Client makes an HTTPS request to the Authorization Server's + Access Token URL using POST. The request contains the following + parameters: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_assertion_format</DT> +<DD> REQUIRED. The + format of the assertion as defined by the Authorization + Server. +</DD> +<DT>wrap_assertion</DT> +<DD> REQUIRED. The + assertion. +</DD> +<DT>wrap_scope</DT> +<DD> OPTIONAL. The Authorization + Server MAY define authorization scope values for the Client to + include +</DD> +<DT>Additional parameters</DT> +<DD> Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_anchor18"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.5.2.4"></A><H3>5.2.4. +Successful Access Token Response from Authorization Server</H3> + +<P>If successful, the Authorization Server returns: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 200 OK +</PRE></DIV> +<P>with the Access Token in the response body. The response body + contains the following parameters: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_access_token</DT> +<DD> REQUIRED. The Access + Token. +</DD> +<DT>wrap_access_token_expires_in</DT> +<DD> OPTIONAL. + The lifetime of the Access Token in seconds. For example, 3600 + represents one hour. +</DD> +<DT>Additional parameters</DT> +<DD> Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<P>The Client may now use the Access Token to access the Protected + Resource per <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_ProtectedResource">Section 4<SPAN> (</SPAN><SPAN>Accessing a Protected Resource</SPAN><SPAN>)</SPAN></A>. +</P> +<A name="0.2_anchor19"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.5.2.5"></A><H3>5.2.5. +Unsuccessful Access Token Response from Authorization Server</H3> + +<P>If the assertion is not valid, the Authorization Server MUST + respond with: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 401 Unauthorized +</PRE></DIV> +<P>and the HTTP header: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> WWW-Authenticate: WRAP +</PRE></DIV> +<P>The Client MUST obtain a valid assertion by repeating <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p2.assertion">Section 5.2.2<SPAN> (</SPAN><SPAN>Client Obtains Assertion</SPAN><SPAN>)</SPAN></A> before retrying the request. +</P> +<A name="0.2_anchor20"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.5.2.6"></A><H3>5.2.6. +Client Refreshes Access Token</H3> + +<P>Authorization Servers SHOULD issue Access Tokens that expire and + require Clients to refresh them. Upon receiving the HTTP 401 + response when accessing protected resources per <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_ProtectedResource">Section 4<SPAN> (</SPAN><SPAN>Accessing a Protected Resource</SPAN><SPAN>)</SPAN></A>, the Client should request a new + Access Token by repeating <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p2.request">Section 5.2.3<SPAN> (</SPAN><SPAN>Client Requests Access Token</SPAN><SPAN>)</SPAN></A> if the + assertion is still valid, otherwise the Client MUST obtain a new, + valid assertion by repeating <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p2.assertion">Section 5.2.2<SPAN> (</SPAN><SPAN>Client Obtains Assertion</SPAN><SPAN>)</SPAN></A>. +</P> +<A name="0.2_user.profiles"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6"></A><H3>6. +Acquiring an Access Token: User Delegation Profiles</H3> + +<P>These are the profiles the Client uses when acting on behalf of a + User. +</P> +<A name="0.2_p3"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.1"></A><H3>6.1. +Username and Password Profile</H3> + +<P>This profile is suitable where the Client is an application the + User has installed on their computer and the User uses a username and + password to authenticate to the Authorization Server. This profile + enables a Client to act on behalf of the User without having to + permanently store the User's username and password. +</P> +<A name="0.2_anchor21"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.1.1"></A><H3>6.1.1. +Provisioning</H3> + +<P>Prior to initiating this protocol profile, the Authorization + Server MAY have required the Client to have obtained a Client + Identifier from the Authorization Server. +</P> +<A name="0.2_p3.password"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.1.2"></A><H3>6.1.2. +Client Obtains Username and Password</H3> + +<P>The Client obtains the User's username and password from the + user. The Client MUST discard the username and password once an + Access Token has been obtained. +</P> +<A name="0.2_p3.request"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.1.3"></A><H3>6.1.3. +Client Requests Access Token</H3> + +<P>The Client makes an HTTPS request to the Authorization Server's + Access Token URL using POST. The request contains the following + parameters: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_client_id</DT> +<DD> REQUIRED. The Client + Identifier. +</DD> +<DT>wrap_username</DT> +<DD> REQUIRED. The User's + username. +</DD> +<DT>wrap_password</DT> +<DD> REQUIRED. The User's + password. +</DD> +<DT>wrap_scope</DT> +<DD> OPTIONAL. The Authorization + Server MAY define authorization scope values for the Client to + include. +</DD> +<DT>Additional parameters</DT> +<DD> Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_anchor22"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.1.4"></A><H3>6.1.4. +Successful Access Token Response from Authorization Server</H3> + +<P>If successful, the Authorization Server returns: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 200 OK +</PRE></DIV> +<P>with the Access Token in the response body. The response body + contains the following parameters: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_access_token</DT> +<DD> REQUIRED. The Access + Token. +</DD> +<DT>wrap_access_token_expires_in</DT> +<DD> OPTIONAL. + The lifetime of the Access Token in seconds. For example, 3600 + represents one hour. +</DD> +<DT>Additional parameters</DT> +<DD> Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<P>The Client MUST discard the User's username and password. The + Client securely stores the Refresh Token for later use. The Client + may now use the Access Token to access the Protected Resource per + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_ProtectedResource">Section 4<SPAN> (</SPAN><SPAN>Accessing a Protected Resource</SPAN><SPAN>)</SPAN></A>. +</P> +<A name="0.2_anchor23"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.1.5"></A><H3>6.1.5. +Unsuccessful Access Token Response from Authorization Server</H3> + +<P>The Authorization Server MUST verify User's username and + password. If the verification fails, the Authorization Server MUST + respond with: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 401 Unauthorized +</PRE></DIV> +<P>and the HTTP header: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> WWW-Authenticate: WRAP +</PRE></DIV> +<P>The Client needs to obtain a valid username and password from the + User per <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p3.password">Section 6.1.2<SPAN> (</SPAN><SPAN>Client Obtains Username and Password</SPAN><SPAN>)</SPAN></A> before retrying the + request. +</P> +<A name="0.2_anchor24"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.1.6"></A><H3>6.1.6. +Verification URL Response from Authorization Server</H3> + +<P>If the Authorization Server determines that the Client may be + malicious, the Authorization Server MAY require the Client to + instruct the User to visit a Verification URL. The Authorization + Server communicates its requirement by responding to the Client's + Access Token request with the following: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 400 Bad Request +</PRE></DIV> +<P>and the body of the Authorization Server response contains the + following parameter: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_verification_url</DT> +<DD>REQUIRED. The + verification URL that the Client MUST either load in the User's + browser, or display for the User to enter into a browser. +</DD> +</DL></BLOCKQUOTE> + +<P>The Client MUST then wait for the User to indicate they have + successfully completed the verification process at the Authorization + Server and attempt to obtain an Access Token Refresh Token per <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p3.request">Section 6.1.3<SPAN> (</SPAN><SPAN>Client Requests Access Token</SPAN><SPAN>)</SPAN></A> again. +</P> +<A name="0.2_anchor25"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.1.7"></A><H3>6.1.7. +CAPTCHA Response from Authorization Server</H3> + +<P>If the Authorization Server determines that the Client may be + malicious, the Authorization Server MAY require the Client to have + the User solve a CAPTCHA Puzzle. The Authorization Server + communicates its requirement by responding to the Client's Access + Token request with the following: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 400 Bad Request +</PRE></DIV> +<P>and the body of the Authorization Server response contains the + following parameter: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_captcha_url</DT> +<DD>REQUIRED. The URL to + the CAPTCHA puzzle image. +</DD> +</DL></BLOCKQUOTE> + +<P>The Client MUST present the User with the CAPTCHA puzzle and + prompt for a solution. The Client then MAY attempt to obtain an + Access Token per <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p3.request">Section 6.1.3<SPAN> (</SPAN><SPAN>Client Requests Access Token</SPAN><SPAN>)</SPAN></A> again, including + the following additional parameter: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_captcha_url</DT> +<DD>REQUIRED. The URL to + the CAPTCHA puzzle received from the Authorization Server. +</DD> +<DT>wrap_captcha_solution</DT> +<DD>REQUIRED. The + solution string to the CAPTCHA puzzle as defined by the + Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_anchor26"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.1.8"></A><H3>6.1.8. +Client Refreshes Access Token</H3> + +<P>Refreshing an Access Token is the same in <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p3">Section 6.1<SPAN> (</SPAN><SPAN>Username and Password Profile</SPAN><SPAN>)</SPAN></A>, <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p4">Section 6.2<SPAN> (</SPAN><SPAN>Web App Profile</SPAN><SPAN>)</SPAN></A>, and <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p5">Section 6.3<SPAN> (</SPAN><SPAN>Rich App Profile</SPAN><SPAN>)</SPAN></A>. Authorization Servers SHOULD issue Access + Tokens that expire and require Clients to refresh them. Upon + receiving the HTTP 401 response when accessing protected resources + per <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_ProtectedResource">Section 4<SPAN> (</SPAN><SPAN>Accessing a Protected Resource</SPAN><SPAN>)</SPAN></A>, the Client makes an + HTTPS request to the Authorization Server's Refresh Token URL using + POST. The request contains the following parameters: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_refresh_token</DT> +<DD>REQUIRED. The Refresh + Token that was received in <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p3.request">Section 6.1.3<SPAN> (</SPAN><SPAN>Client Requests Access Token</SPAN><SPAN>)</SPAN></A> +</DD> +<DT>Additional parameters:</DT> +<DD>Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_anchor27"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.1.9"></A><H3>6.1.9. +Successful Access Token Refresh</H3> + +<P>If successful, the Authorization Server returns: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 200 OK +</PRE></DIV> +<P>with the Access Token in the response body. The response body + contains the following parameters: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_access_token</DT> +<DD> REQUIRED. The Access + Token. +</DD> +<DT>wrap_access_token_expires_in</DT> +<DD> OPTIONAL. + The lifetime of the Access Token in seconds. For example, 3600 + represents one hour. +</DD> +<DT>Additional parameters</DT> +<DD> Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_anchor28"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.1.10"></A><H3>6.1.10. +Unsuccessful Access Token Refresh</H3> + +<P>The Authorization Server MUST verify the Refresh Token. If the + verification fails, the Authorization Server MUST respond with +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 401 Unauthorized +</PRE></DIV> +<P>and the HTTP header: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> WWW-Authenticate: WRAP +</PRE></DIV> +<P>The Client MUST again request authorization from the User by + prompting for the User's username and password per <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p3.password">Section 6.1.2<SPAN> (</SPAN><SPAN>Client Obtains Username and Password</SPAN><SPAN>)</SPAN></A> before retrying the request. +</P> +<A name="0.2_p4"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.2"></A><H3>6.2. +Web App Profile</H3> + +<P>This profile is suitable when the Client is a web application + calling the Protected Resource on behalf of a User. This profile + enables a Client to act on behalf of the User without acquiring a + User's credentials. +</P> +<A name="0.2_anchor29"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.2.1"></A><H3>6.2.1. +Provisioning</H3> + +<P>Prior to initiating this protocol profile, the Client MUST have + obtained a Client Identifier and Client Secret from the + Authorization Server. The Authorization Server MAY have also + required the Client to register the Callback URL. +</P> +<A name="0.2_p4.authorization"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.2.2"></A><H3>6.2.2. +Client Directs the User to the Authorization Server</H3> + +<P>The Client initiates an authorization request by redirecting the + User's browser to the Authorization Server's User Authorization URL, + with the following parameters: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_client_id</DT> +<DD> REQUIRED. The Client + Identifier. +</DD> +<DT>wrap_callback </DT> +<DD> REQUIRED. The + Callback URL. An absolute URL to which the Authorization Server + will redirect the User back after the User has approved the + authorization request. Authorization Servers MAY require that + the wrap_callback URL match the previously registered value for + the Client Identifier. +</DD> +<DT>wrap_client_state</DT> +<DD>OPTIONAL. An opaque + value that Clients can use to maintain state associated with + this request. If this value is present, the Authorization Server + MUST return it to the Client's Callback URL. +</DD> +<DT>wrap_scope</DT> +<DD> OPTIONAL. The Authorization + Server MAY define authorization scope values for the Client to + include. +</DD> +<DT>Additional parameters</DT> +<DD> Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_anchor30"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.2.3"></A><H3>6.2.3. +Authorization Server Confirms Authorization Request with User</H3> + +<P>Upon receiving an authorization request from the Client by a + redirection of the User's browser, the Authorization Server + authenticates the user, presents the User with the Protected + Resource access that will be granted to the Client, and prompts the + User to confirm the request. +</P> +<P>If the User denies the request, the Authorization Server MAY + allow the User to return to the Client Callback URL with the + following parameters added: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_error_reason</DT> +<DD> REQUIRED. Value is + user_denied +</DD> +<DT>wrap_client_state</DT> +<DD> REQUIRED if the + Client sent the value in the authorization request in <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p4.authorization">Section 6.2.2<SPAN> (</SPAN><SPAN>Client Directs the User to the Authorization Server</SPAN><SPAN>)</SPAN></A> +</DD> +</DL></BLOCKQUOTE> + +<P>If the User approves the request, the Authorization Server + generates a Verification Code and associates it with the Client + Identifier and Callback URL. +</P> +<A name="0.2_anchor31"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.2.4"></A><H3>6.2.4. +Authorization Server Directs User back to the Client</H3> + +<P>If the User approved the request, the Authorization Server MUST + redirect the User back to the Callback URL, with the following + parameters added: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_verification_code</DT> +<DD> REQUIRED. The + Verification Code. +</DD> +<DT>wrap_client_state</DT> +<DD> REQUIRED if the + Client sent the value in the authorization request in <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p4.authorization">Section 6.2.2<SPAN> (</SPAN><SPAN>Client Directs the User to the Authorization Server</SPAN><SPAN>)</SPAN></A> +</DD> +<DT>Additional parameters:</DT> +<DD>Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_p4.request"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.2.5"></A><H3>6.2.5. +Client Requests Access Token</H3> + +<P>The Client makes an HTTPS request to the Authorization Server's + Access Token URL, using POST. The request contains the following + parameters in the body of the request: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_client_id</DT> +<DD> REQUIRED. The Client + Identifier +</DD> +<DT>wrap_client_secret</DT> +<DD>REQUIRED. The Client + Secret +</DD> +<DT>wrap_verification_code</DT> +<DD> REQUIRED. The + Verification Code. +</DD> +<DT>wrap_callback</DT> +<DD> REQUIRED. The Callback + URL used to obtain the Verification Code. +</DD> +<DT>Additional parameters:</DT> +<DD>Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_anchor32"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.2.6"></A><H3>6.2.6. +Successful Access Token Response from Authorization Server</H3> + +<P>After receiving the Access Token request, the Authorization + Server verifies the request as follows: +</P> +<P></P> +<BLOCKQUOTE> +<P>the Client Secret MUST match the Client Identifer +</P> +<P>the Client Identifier MUST match the Client Identifier from + the authorization redirect +</P> +<P>the Verification Code MUST match the Client Identifier from + the authorization redirect +</P> +<P>the Callback URL MUST match the Callback URL from the + authorization redirect +</P> +<P>if the Callback URL or Callback URL pattern was registered + with the Authorization Server, the Callback URL MUST match the + Callback URL or Callback URL pattern as defined by the + Authorization Server +</P> +<P>the Verification Code MUST not have expired +</P> +</BLOCKQUOTE> + +<P>The Authorization Server MAY also require that a Verification + Code is not reused. +</P> +<P>If verification is successful, the Authorization Server + returns: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 200 OK +</PRE></DIV> +<P>with the Refresh Token and the Access Token in the response body. + The response body contains the following parameters: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_refresh_token</DT> +<DD> REQUIRED. The + Refresh Token. +</DD> +<DT>wrap_access_token</DT> +<DD> REQUIRED. The Access + Token. +</DD> +<DT>wrap_access_token_expires_in</DT> +<DD> OPTIONAL. + The lifetime of the Access Token in seconds. For example, 3600 + represents one hour. +</DD> +<DT>Additional parameters</DT> +<DD> Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<P>The Client securely stores the Refresh Token for later use. The + Client may now use the Access Token to access the Protected Resource + per <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_ProtectedResource">Section 4<SPAN> (</SPAN><SPAN>Accessing a Protected Resource</SPAN><SPAN>)</SPAN></A>. +</P> +<A name="0.2_anchor33"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.2.7"></A><H3>6.2.7. +Unsuccessful Access Token Response from Authorization Server</H3> + +<P>The Authorization Server MUST first verify the Client Identifier + and Client Secret. If they are invalid, the Authorization Server + MUST respond with: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 401 Unauthorized +</PRE></DIV> +<P>and the HTTP header: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> WWW-Authenticate: WRAP +</PRE></DIV> +<P>The Client MUST obtain a valid Client Identifier and Client + Secret before retrying the request. +</P> +<P>The Authorization Server MUST then verify that the Callback URL + and Verification Code are associated with the Client Identifier. If + the verification fails, the Authorization Server MUST respond + with: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 400 Bad Request +</PRE></DIV> +<P>and the body of the Authorization Server response contains the + following parameters: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_error_reason</DT> +<DD>OPTIONAL. If all the + parameters are valid except that the Verification Code has + expired or been revoked, then it is RECOMMENDED that this + parameter be included and if so, then the value MUST be: +</DD> +<DT> +<DD><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> expired_verification_code +</PRE></DIV> +</DD> +<DT> +<DD>This enables the Client to detect it needs a new Verification + Code and to direct the User to the Authorization Server per + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p4.authorization">Section 6.2.2<SPAN> (</SPAN><SPAN>Client Directs the User to the Authorization Server</SPAN><SPAN>)</SPAN></A> +</DD> +<DT> +<DD>If the Callback URL is invalid, the value MUST be: +</DD> +<DT> +<DD><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> invalid_callback +</PRE></DIV> +</DD> +<DT>Additional parameters</DT> +<DD> Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_anchor34"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.2.8"></A><H3>6.2.8. +Client Refreshes Access Token</H3> + +<P>Refreshing an Access Token is the same in <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p3">Section 6.1<SPAN> (</SPAN><SPAN>Username and Password Profile</SPAN><SPAN>)</SPAN></A>, <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p4">Section 6.2<SPAN> (</SPAN><SPAN>Web App Profile</SPAN><SPAN>)</SPAN></A>, and <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p5">Section 6.3<SPAN> (</SPAN><SPAN>Rich App Profile</SPAN><SPAN>)</SPAN></A>. Authorization Servers SHOULD issue Access + Tokens that expire and require Clients to refresh them. Upon + receiving the HTTP 401 response when accessing protected resources + per <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_ProtectedResource">Section 4<SPAN> (</SPAN><SPAN>Accessing a Protected Resource</SPAN><SPAN>)</SPAN></A>, the Client makes an + HTTPS request to the Authorization Server's Refresh Token URL using + POST. The request contains the following parameters: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_refresh_token</DT> +<DD>REQUIRED. The Refresh + Token that was received in <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p4.request">Section 6.2.5<SPAN> (</SPAN><SPAN>Client Requests Access Token</SPAN><SPAN>)</SPAN></A> +</DD> +<DT>Additional parameters:</DT> +<DD>Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_anchor35"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.2.9"></A><H3>6.2.9. +Successful Access Token Refresh</H3> + +<P>If successful, the Authorization Server returns: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 200 OK +</PRE></DIV> +<P>with the Access Token in the response body. The response body + contains the following parameters: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_access_token</DT> +<DD> REQUIRED. The Access + Token. +</DD> +<DT>wrap_access_token_expires_in</DT> +<DD> OPTIONAL. + The lifetime of the Access Token in seconds. For example, 3600 + represents one hour. +</DD> +<DT>Additional parameters</DT> +<DD> Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_anchor36"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.2.10"></A><H3>6.2.10. +Unsuccessful Access Token Refresh</H3> + +<P>The Authorization Server MUST verify the Refresh Token. If the + verification fails, the Authorization Server MUST respond with +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 401 Unauthorized +</PRE></DIV> +<P>and the HTTP header: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> WWW-Authenticate: WRAP +</PRE></DIV> +<P>The Client MUST again request authorization from the User per + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p4.authorization">Section 6.2.2<SPAN> (</SPAN><SPAN>Client Directs the User to the Authorization Server</SPAN><SPAN>)</SPAN></A>. +</P> +<A name="0.2_p5"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.3"></A><H3>6.3. +Rich App Profile</H3> + +<P>This profile is suitable where the Client is an application the + User has installed on their computer and there is a browser available + for the Client to launch. This profile enables a Client to act on + behalf of the User regardless of how the User authenticates to the + Server and without access to the User's credentials. +</P> +<A name="0.2_anchor37"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.3.1"></A><H3>6.3.1. +Provisioning</H3> + +<P>Prior to initiating this protocol profile, the Client MAY be + required to register the Client Identifier and/or the Callback URL + with the Server. +</P> +<A name="0.2_p5.authorization"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.3.2"></A><H3>6.3.2. +Client Directs the User to the Authorization Server</H3> + +<P>The Client initiates an authorization request by opening the + User's browser with the Server's User Authorization URL, and + including the following parameters: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_client_id</DT> +<DD> REQUIRED. The Client + Identifier. +</DD> +<DT>wrap_callback </DT> +<DD> OPTIONAL. A Callback + URL where the Authorization Server MAY redirect the User's + browser after the User responds to the authorization + request. +</DD> +<DT>wrap_client_state</DT> +<DD>OPTIONAL. An opaque + value that Clients can use to maintain state associated with + this request. If this value is present, the Authorization Server + MUST return it to the Client's Callback URL. +</DD> +<DT>wrap_scope</DT> +<DD> OPTIONAL. The Authorization + Server MAY define authorization scope values for the Client to + include. +</DD> +<DT>Additional parameters</DT> +<DD> Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_anchor38"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.3.3"></A><H3>6.3.3. +Authorization Server Confirms Authorization Request with User</H3> + +<P>Upon receiving an authorization request from the Client by way of + the User's browser, the Authorization Server authenticates the user, + presents the User with the Protected Resource access that will be + granted to the Client, and prompts the User to confirm the request. + If the User approves the request, the Authorization Server generates + a Verification Code. If the User denied access, the Authorization + Server MAY set the Verification Code to the reserved value: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> user_denied +</PRE></DIV> +<P>It is RECOMMENDED the Verification Code be single use, and expire + within minutes of issue. There are a number of mechanisms for the + Authorization Server to transmit the Verification Code to the + Client, specified below. +</P> +<P>Rich Application interaction with the User and the Authorization + Server is an area of active research and development. If the Rich + Application is able to retrieve the verifier directly from the + callback URL returned by the Authorization Server, an improved user + experience is possible. However, not all applications are able to + interact with the Authorization Server in this manner. +</P> +<A name="0.2_anchor39"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.3.3.1"></A><H3>6.3.3.1. +Applications with Callback URLs</H3> + +<P>Rich Applications may be able to receive callback URLs in any + of several ways. For example, the Rich Application may register a + custom protocol handler with the application platform so that the + application will be invoked when the browser is redirected to the + callback URL. Alternatively, the callback URL may point to a web + site with which the Rich Application has a trust relationship. The + web site can then pass the Callback URL down to the Rich + Application for processing. Finally, the Callback URL may point to + a web site that will display the Callback URL to the screen along + with instructions for the user to enter the Verification Code into + the application. +</P> +<P>For Rich Applications with a Callback URL, the Authorization + Server MUST redirect the User back to the Callback URL, with the + following parameters added: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_verification_code</DT> +<DD> REQUIRED. The + Verification Code +</DD> +<DT>wrap_client_state</DT> +<DD> REQUIRED if the + Client sent the value in the authorization request in <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p5.authorization">Section 6.3.2<SPAN> (</SPAN><SPAN>Client Directs the User to the Authorization Server</SPAN><SPAN>)</SPAN></A> +</DD> +<DT>Additional parameters</DT> +<DD> Any + additional parameters, as defined by the Authorization + Server. +</DD> +</DL></BLOCKQUOTE> + +<P>If the User denied access, the Server MAY redirect the User's + browser to the Callback URL with the Verification Code set to the + reserved value: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> user_denied +</PRE></DIV> +<A name="0.2_anchor40"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.3.3.2"></A><H3>6.3.3.2. +Applications without Callback URLs</H3> + +<P>Rich Applications without Callback URLs need to receive the + verification code in other ways. For Rich Applications without a + Callback URL, the Authorization Server MUST present the + Verification Code on the web page and instruct the user to enter + it into the Client. +</P> +<P>The Server MAY also append the Verification Code to the title + of the HTML page so that Clients that have access to the title of + the browser's current page can obtain the Verification Code + without requiring the User enter the Verification Code into the + Client. The Client can parse the title looking for "code=" and + then the rest of the title is the Verification Code. If adding the + Verification Code to the title of the HTML page, the Server MUST + also include the wrap_client_state parameter if sent from the + Client as the "state=" parameter. +</P> +<P>Eg. For <A href="http://example.com/" target="_blank">example.com</A> where the Verification Code = WF34F7HG and + Client State = NMMGFJJ, the Server would set the title of the page + to something like: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> <title>Successful delegation, code=WF34F7HG +state=NMMGFJJ</title></PRE></DIV> +<P>If the User denied access, the Server MAY append + code=user_denied to the title of the HTML page so that the Client + can detect that the User has denied access. +</P> +<A name="0.2_p5.request"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.3.4"></A><H3>6.3.4. +Client Requests Access Token</H3> + +<P>The Client makes an HTTPS request to the Server's Access Token + URL using POST. The request contains the following parameters: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_client_id</DT> +<DD> REQUIRED. The Client + Identifier +</DD> +<DT>wrap_verification_code</DT> +<DD> REQUIRED. The + Verification Code. +</DD> +<DT>Additional parameters:</DT> +<DD>Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_p5.verification"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.3.5"></A><H3>6.3.5. +Successful Access Token Response from Authorization Server</H3> + +<P>The Server checks the Verification Code was previously issued to + the same Client Identifier, has not expired and has not been used. + If these conditions are met, the Server marks the Verification Code + as being used and returns: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 200 OK +</PRE></DIV> +<P>with the Refresh Token and an Access Token in the response body. + The response body contains the following parameters: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_refresh_token</DT> +<DD> REQUIRED. The + Refresh Token. +</DD> +<DT>wrap_access_token</DT> +<DD> REQUIRED. The Access + Token. +</DD> +<DT>wrap_access_token_expires_in</DT> +<DD> OPTIONAL. + The lifetime of the Access Token in seconds. For example, 3600 + represents one hour. +</DD> +<DT>Additional parameters</DT> +<DD> Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<P>The Client securely stores the Refresh Token for later use. The + Client may now use the Access Token to access the Protected Resource + per <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_ProtectedResource">Section 4<SPAN> (</SPAN><SPAN>Accessing a Protected Resource</SPAN><SPAN>)</SPAN></A>. +</P> +<A name="0.2_anchor41"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.3.6"></A><H3>6.3.6. +Unsuccessful Access Token Response from Authorization Server</H3> + +<P>The Authorization Server MUST first verify the Client Identifier + and Client Secret per <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p5.verification">Section 6.3.5<SPAN> (</SPAN><SPAN>Successful Access Token Response from Authorization Server</SPAN><SPAN>)</SPAN></A>. If + they are invalid, the Authorization Server MUST respond with: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 401 Unauthorized +</PRE></DIV> +<P>and the HTTP header: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> WWW-Authenticate: WRAP +</PRE></DIV> +<P>The Client needs to obtain a new Verification Code per <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p5.authorization">Section 6.3.2<SPAN> (</SPAN><SPAN>Client Directs the User to the Authorization Server</SPAN><SPAN>)</SPAN></A>. +</P> +<A name="0.2_anchor42"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.3.7"></A><H3>6.3.7. +Client Refreshes Access Token</H3> + +<P>Refreshing an Access Token is the same in <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p3">Section 6.1<SPAN> (</SPAN><SPAN>Username and Password Profile</SPAN><SPAN>)</SPAN></A>, <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p4">Section 6.2<SPAN> (</SPAN><SPAN>Web App Profile</SPAN><SPAN>)</SPAN></A>, and <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p5">Section 6.3<SPAN> (</SPAN><SPAN>Rich App Profile</SPAN><SPAN>)</SPAN></A>. Authorization Servers SHOULD issue Access + Tokens that expire and require Clients to refresh them. Upon + receiving the HTTP 401 response when accessing protected resources + per <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_ProtectedResource">Section 4<SPAN> (</SPAN><SPAN>Accessing a Protected Resource</SPAN><SPAN>)</SPAN></A>, the Client makes an + HTTPS request to the Authorization Server's Refresh Token URL using + POST. The request contains the following parameters: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_refresh_token</DT> +<DD>REQUIRED. The Refresh + Token that was received in <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p5.request">Section 6.3.4<SPAN> (</SPAN><SPAN>Client Requests Access Token</SPAN><SPAN>)</SPAN></A> +</DD> +<DT>Additional parameters:</DT> +<DD>Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_anchor43"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.3.8"></A><H3>6.3.8. +Successful Access Token Refresh</H3> + +<P>If successful, the Authorization Server returns: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 200 OK +</PRE></DIV> +<P>with the Access Token in the response body. The response body + contains the following parameters: +</P> +<P></P> +<BLOCKQUOTE><DL> +<DT>wrap_access_token</DT> +<DD> REQUIRED. The Access + Token. +</DD> +<DT>wrap_access_token_expires_in</DT> +<DD> OPTIONAL. + The lifetime of the Access Token in seconds. For example, 3600 + represents one hour. +</DD> +<DT>Additional parameters</DT> +<DD> Any additional + parameters, as defined by the Authorization Server. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_anchor44"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.6.3.9"></A><H3>6.3.9. +Unsuccessful Access Token Refresh</H3> + +<P>The Authorization Server MUST verify the Refresh Token. If the + verification fails, the Authorization Server MUST respond with +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> HTTP 401 Unauthorized +</PRE></DIV> +<P>and the HTTP header: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> WWW-Authenticate: WRAP +</PRE></DIV> +<P>The Client MUST again request authorization from the User per + <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_p5.authorization">Section 6.3.2<SPAN> (</SPAN><SPAN>Client Directs the User to the Authorization Server</SPAN><SPAN>)</SPAN></A>. +</P> +<A name="0.2_ParamCon"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.7"></A><H3>7. +Parameter Considerations</H3> + +<A name="0.2_anchor45"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.7.1"></A><H3>7.1. +Authorization Server Request / Response Parameter Encoding</H3> + +<P>All requests made directly to the Authorization Server use the HTTP + POST method and the parameters MUST be in the body of the message and + formatted as application/x-www-form-<WBR>urlencoded per <A href="http://www.w3.org/TR/1999/REC-W3C.REC-html40-19980424-19991224/interact/forms.html#h-17.13.4.1" target="_blank">17.13.4</A> + of <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_W3C.REC-html40-19980424">HTML 4.01<SPAN> (</SPAN><SPAN>Hors, A., Jacobs, I., and D. Raggett, “HTML 4.0 Specification,” April 1998.</SPAN><SPAN>)</SPAN></A> [W3C.REC‑html40‑19980424]. +</P> +<P>Any parameters in the response from the Authorization Server MUST + be in the body of the message and formatted as + application/x-www-form-<WBR>urlencoded per <A href="http://www.w3.org/TR/1999/REC-W3C.REC-html40-19980424-19991224/interact/forms.html#h-17.13.4.1" target="_blank">17.13.4</A> + of <A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_W3C.REC-html40-19980424">HTML 4.01<SPAN> (</SPAN><SPAN>Hors, A., Jacobs, I., and D. Raggett, “HTML 4.0 Specification,” April 1998.</SPAN><SPAN>)</SPAN></A> [W3C.REC‑html40‑19980424]. +</P> +<A name="0.2_anchor46"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.7.2"></A><H3>7.2. +Parameter Size</H3> + +<P></P> +<BLOCKQUOTE><DL> +<DT>HTTP Headers</DT> +<DD> Web servers often impose a + maximum on the combined size of all HTTP headers ranging from 8KB + to 16KB. The size of the Access Token should be small enough to + ensure the total size of the HTTP headers does not exceed the + limits of web servers. +</DD> +<DT>URLs</DT> +<DD> Web servers and browsers often + impose a maximum on the total length of the URL of as low as 2083 + bytes. The length of URLs exposed by the Authorization Server and + the length of parameters passed on a URL should be minimized so + that the total length does not exceed this limit. +</DD> +</DL></BLOCKQUOTE> + +<A name="0.2_anchor47"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.7.3"></A><H3>7.3. +Access Token Format</H3> + +<P>OAuth WRAP does not specify the format of the Access Token. The + format is mutually agreed to by the Authorization Server and the + Protected Resource and is opaque to the Client. The Access Token + format MUST consist of legal characters in an HTTP header per + [Reference needed] +</P> +<P>The Simple Web Token (SWT) and JSON Web Token (JWT) are possible + Access Token formats. +</P> +<P>[TBD: entropy recommendations for Access Token so that it remains + secure during its lifetime] +</P> +<A name="0.2_anchor48"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.7.4"></A><H3>7.4. +Refresh Token Format</H3> + +<P>OAuth WRAP does not specify the format of the Refresh Token. The + Refresh Token is both generated and consumed by the Authorization + Server and is opaque to the Client and never exposed to the Protected + Resource. The Refresh Token is a long lived credential, and should + contain enough entropy that it cannot be guessed. The size limitations + of the Access Token are not applicable to the Refresh Token as the + Refresh Token is always in the body of an HTTP message. +</P> +<A name="0.2_anchor49"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.7.5"></A><H3>7.5. +Additional Authorization Server Parameters</H3> + +<P>The Authorization Server may define additional parameters to be + included in are returned from calls to the Access Token URL or User + Authorization URL. Parameters that start with wrap_ are reserved and + may not be used. +</P> +<A name="0.2_anchor50"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.7.6"></A><H3>7.6. +Parameter Names and Order</H3> + +<P>All parameter names are case sensitive. The parameters my appear in + any order. Unrecognized parameters are allowed, but MUST be + ignored. +</P> +<A name="0.2_IANA"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.8"></A><H3>8. +IANA Considerations</H3> + +<P>This memo includes no request to IANA. +</P> +<A name="0.2_Security"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.9"></A><H3>9. +Security Considerations</H3> + +<P>TBD: need to put in all the security considerations for + implementors. +</P> +<A name="0.2_rfc.references"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.10"></A><H3>10. +References</H3> + +<A name="0.2_rfc.references1"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<H3>10.1. Normative References</H3> +<TABLE width="99%" border="0"> +<TBODY><TR><TD valign="top"><A name="0.2_RFC2119">[RFC2119]</A></TD> +<TD><A href="mailto:sob@harvard.edu" target="_blank">Bradner, S.</A>, “<A href="http://tools.ietf.org/html/rfc2119" target="_blank">Key words for use in RFCs to Indicate Requirement Levels</A>,” BCP 14, RFC 2119, March 1997 (<A href="ftp://ftp.isi.edu/in-notes/rfc2119.txt" target="_blank">TXT</A>, <A href="http://xml.resource.org/public/rfc/html/rfc2119.html" target="_blank">HTML</A>, <A href="http://xml.resource.org/public/rfc/xml/rfc2119.xml" target="_blank">XML</A>).</TD></TR> +<TR><TD valign="top"><A name="0.2_RFC2606">[RFC2606]</A></TD> +<TD><A href="mailto:dee3@us.ibm.com" target="_blank">Eastlake, D.</A> and <A href="mailto:buglady@fuschia.net" target="_blank">A. Panitz</A>, “<A href="http://tools.ietf.org/html/rfc2606" target="_blank">Reserved Top Level DNS Names</A>,” BCP 32, RFC 2606, June 1999 (<A href="ftp://ftp.isi.edu/in-notes/rfc2606.txt" target="_blank">TXT</A>).</TD></TR> +<TR><TD valign="top"><A name="0.2_RFC2617">[RFC2617]</A></TD> +<TD><A href="mailto:john@math.nwu.edu" target="_blank">Franks, J.</A>, <A href="mailto:pbaker@verisign.com" target="_blank">Hallam-Baker, P.</A>, <A href="mailto:jeff@AbiSource.com" target="_blank">Hostetler, J.</A>, <A href="mailto:lawrence@agranat.com" target="_blank">Lawrence, S.</A>, <A href="mailto:paulle@microsoft.com" target="_blank">Leach, P.</A>, Luotonen, A., and <A href="mailto:stewart@OpenMarket.com" target="_blank">L. Stewart</A>, “<A href="http://tools.ietf.org/html/rfc2617" target="_blank">HTTP Authentication: Basic and Digest Access Authentication</A>,” RFC 2617, June 1999 (<A href="ftp://ftp.isi.edu/in-notes/rfc2617.txt" target="_blank">TXT</A>, <A href="http://xml.resource.org/public/rfc/html/rfc2617.html" target="_blank">HTML</A>, <A href="http://xml.resource.org/public/rfc/xml/rfc2617.xml" target="_blank">XML</A>).</TD></TR> +<TR><TD valign="top"><A name="0.2_W3C.REC-html40-19980424">[W3C.REC-html40-19980424]</A></TD> +<TD>Hors, A., Jacobs, I., and D. Raggett, “<A href="http://www.w3.org/TR/1998/REC-html40-19980424" target="_blank">HTML 4.0 Specification</A>,” World Wide Web Consortium Recommendation REC-html40-<WBR>19980424, April 1998 (<A href="http://www.w3.org/TR/1998/REC-html40-19980424" target="_blank">HTML</A>).</TD></TR> +</TBODY></TABLE> + +<A name="0.2_rfc.references2"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<H3>10.2. Informative References</H3> +<TABLE width="99%" border="0"> +<TBODY><TR><TD valign="top"><A name="0.2_I-D.narten-iana-considerations-rfc2434bis">[I-D.narten-iana-<WBR>considerations-rfc2434bis]</A></TD> +<TD>Narten, T. and H. Alvestrand, “<A href="http://www.ietf.org/internet-drafts/draft-narten-iana-considerations-rfc2434bis-09.txt" target="_blank">Guidelines for Writing an IANA Considerations Section in RFCs</A>,” draft-narten-iana-<WBR>considerations-rfc2434bis-09 (work in progress), March 2008 (<A href="http://www.ietf.org/internet-drafts/draft-narten-iana-considerations-rfc2434bis-09.txt" target="_blank">TXT</A>).</TD></TR> +<TR><TD valign="top"><A name="0.2_OASIS.saml-core-2.0-os">[OASIS.saml-core-2.0-os]</A></TD> +<TD><A href="mailto:cantor.2@osu.edu" target="_blank">Cantor, S.</A>, <A href="mailto:John.Kemp@nokia.com" target="_blank">Kemp, J.</A>, <A href="mailto:rphilpott@rsasecurity.com" target="_blank">Philpott, R.</A>, and <A href="mailto:eve.maler@sun.com" target="_blank">E. Maler</A>, “<A href="http://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf" target="_blank">Assertions and Protocol for the OASIS Security Assertion Markup Language + (SAML) V2.0</A>,” OASIS Standard saml-core-2.0-os, March 2005.</TD></TR> +<TR><TD valign="top"><A name="0.2_OAuth Core 1.0">[OAuth Core 1.0]</A></TD> +<TD>Hammer-Lahav, E., “<A href="http://tools.ietf.org/html/draft-hammer-oauth-08" target="_blank">OAuth Core 1.0 Protocol</A>.”</TD></TR> +</TBODY></TABLE> + +<A name="0.2_anchor53"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.A"></A><H3>Appendix A. +Client Account and Password Profile Example</H3> + +<P>In this example, <A href="http://crm.example.com/" target="_blank">crm.example.com</A> is an application server that has a + Protected Resource at <A href="https://crm.example.com/data" target="_blank">https://crm.example.com/data</A>. DataDumper is an + application acting as a Client that periodically calls + <A href="https://crm.example.com/data" target="_blank">https://crm.example.com/data</A>. The Protected Resource trusts the + Authorization Server <A href="http://auth.example.net/" target="_blank">auth.example.net</A> to determine if a Client has + access. +</P> +<A name="0.2_anchor54"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.A.1"></A><H3>A.1. +Provisioning</H3> + +<P>The Authorization Server documentation defines the Access Token URL + as: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> <A href="https://auth.example.net/access_token" target="_blank">https://auth.example.net/<WBR>access_token</A> +</PRE></DIV> +<P>The Authorization Server has defined that the parameter Audience be + included in calls to the Access Token URL. +</P> +<P>The Client has been provisioned with the following: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> Client Account: datadumper Client Password: j2hw7GPsl0 +</PRE></DIV> +<P>The Protected Resource and the Authorization Server have agreed to + use a Simple Web Token (SWT) for the Access Token with the reserved + attributes Issuer, Audience, ExpiresOn and the public attribute + net.example.auth.account and have exchanged the following HMAC key + value (expressed in base 64): +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>3iK5ZYAoBQuOqSgF/<WBR>YqlDw70HKRmbyXkrl5f4SJ4Toc= +</PRE></DIV> +<A name="0.2_anchor55"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.A.2"></A><H3>A.2. +Client Requests Access Token</H3> + +<P>The Client makes an HTTPS POST to: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE><A href="https://auth.example.net/access_token" target="_blank">https://auth.example.net/<WBR>access_token</A> +</PRE></DIV> +<P>With the following message body: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>wrap_name=datadumper&wrap_<WBR>password=j2hw7GPsl0&Audience=<A href="http://crm.example.com/" target="_blank">c<WBR>rm.example.com</A> +</PRE></DIV> +<A name="0.2_anchor56"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.A.3"></A><H3>A.3. +Successful Access Token Response from Authorization Server</H3> + +<P>The Authorization Server checks that the Client Password j2hw7GPsl0 + is associated with the Client Name datadumper and that the Client is + authorized to access <A href="http://crm.example.com/" target="_blank">crm.example.com</A>. The Authorization Server notes + the time is 2010-02-03T04:05:06Z, which is 1265198706 seconds since + 1970-01-01T0:0:0Z. The Authorization Server would like the Access + Token to expire in an hour, so 3600 is added to the current time. The + Authorization Server then uses the values: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>net.example.auth.account: +datadumper ExpiresOn: 1265202306 (1265198706 + 3600) +Audience: <A href="http://crm.example.com/" target="_blank">crm.example.com</A> +Issuer: <A href="http://auth.example.net/" target="_blank">auth.example.net</A> +</PRE></DIV> +<P>and the agreed HMAC key to generate the following SWT: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>net.example.auth.account=<WBR>datadumper&ExpiresOn=<WBR>1265202306&Audience=crm. +<A href="http://example.com/" target="_blank">example.com</A>&Issuer=<A href="http://auth.example.net/" target="_blank">auth.<WBR>example.net</A>&HMACSHA256=N9%2F%<WBR>2F0tSos78Me36%2Bi +oBH0sFKfd7eCsURlEIheoUbCJk%3D +</PRE></DIV> +<P>The Authorization Server then responds to the Clients HTTPS request + with: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>HTTP 200 OK +</PRE></DIV> +<P>and the Access Token and lifetime of the Access Token as + application/x-www-form-<WBR>urlencoded data in the body of the message as + such: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>wrap_access_token=net.example.<WBR>auth.account%3Ddatadumper%<WBR>26ExpiresOn%3D +1265202306%26Audience%<A href="http://3dcrm.example.com/" target="_blank">3Dcrm.<WBR>example.com</A>%26Issuer%<A href="http://3dauth.example.net/" target="_blank">3Dauth.<WBR>example.net</A>%26 +HMACSHA256%3DN9%252F%<WBR>252F0tSos78Me36%<WBR>252BioBH0sFKfd7eCsURlEIheoUbCJ<WBR>k%2 +53D&wrap_access_token_expires_<WBR>in=3600</PRE></DIV> +<A name="0.2_anchor57"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.A.4"></A><H3>A.4. +Client Calls Protected Resource</H3> + +<P>The Client now has an Access Token valid for an hour. The Client + makes an API call to: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE><A href="https://crm.example.com/data" target="_blank">https://crm.example.com/data</A> +</PRE></DIV> +<P>including the following HTTP header: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>Authorization: WRAP access_token="net.example.<WBR>auth.account=datadumper& +ExpiresOn=1265202306&Audience=<A href="http://crm.example.com/" target="_blank"><WBR>crm.example.com</A>&Issuer=<A href="http://auth.example.net/" target="_blank">auth.<WBR>example.net</A>& +HMACSHA256=N9%2F%<WBR>2F0tSos78Me36%<WBR>2BioBH0sFKfd7eCsURlEIheoUbCJk%<WBR>3D" +</PRE></DIV> +<P>The Protected Resources verifies the SWT and performs the Client's + request per the authorization attributes in the SWT. +</P> +<A name="0.2_anchor58"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.B"></A><H3>Appendix B. +Web App Profile Example</H3> + +<P>In this example, Jane, the User, listens to music from + <A href="http://music.example.com/" target="_blank">music.example.com</A> and updates her status at <A href="http://status.example.com/" target="_blank">status.example.com</A>. When + listening to music, Jane would like her status to be updated at the + start of each song. From an OAuth WRAP perspective, the Client is + <A href="http://music.example.com/" target="_blank">music.example.com</A>, the Protected Resource is + <A href="https://status.example.com/update" target="_blank">https://status.example.com/<WBR>update</A>, and <A href="http://auth.example.com/" target="_blank">auth.example.com</A> is the + Authorization Server trusted by <A href="http://status.example.com/" target="_blank">status.example.com</A>. +</P> +<A name="0.2_anchor59"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.B.1"></A><H3>B.1. +Provisioning</H3> + +<P>The Authorization Server documentation defines the following + URLs: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE> User Authorization URL: <A href="https://auth.example.com/user_authorization" target="_blank">https://auth.example.com/user_<WBR>authorization</A> + Access Token URL: <A href="https://auth.example.com/access_token" target="_blank">https://auth.example.com/<WBR>access_token</A> + Refresh Token URL: <A href="https://auth.example.com/refresh_token" target="_blank">https://auth.example.com/<WBR>refresh_token</A> +</PRE></DIV> +<P>The Authorization Server has defined that if the Client wants + authorization to update a User's status, that the Client include the + wrap_scope parameter with the value status_update when requesting + authorization. +</P> +<P>The Client has been provisioned with: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>Client Identifier: <A href="http://music.example.com/" target="_blank">music.example.com</A> +Client Secret: 7F2986DF2342914A +</PRE></DIV> +<P>The Client has registered the Callback URL: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE><A href="https://music.example.com/auth_callback" target="_blank">https://music.example.com/<WBR>auth_callback</A> +</PRE></DIV> +<P>The Protected Resource and the Authorization Server have agreed to + use a Simple Web Token (SWT) for the Access Token with the reserved + attributes Issuer, Audience, ExpiresOn and the public attributes + com.example.auth.account, com.example.auth.client and + com.example.auth.scope. They have exchanged the following HMAC key + value (expressed in base 64): +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>Zt9JlL1QvPYRSCK9PgSjrxRUBWe7lb<WBR>EYsZCdM+sJCF4= +</PRE></DIV> +<A name="0.2_anchor60"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.B.2"></A><H3>B.2. +Client Directs the User to the Server</H3> + +<P>Jane informs <A href="http://music.example.com/" target="_blank">music.example.com</A> that she would like her status at + <A href="http://status.example.com/" target="_blank">status.example.com</A> to be updated when a new song starts playing. The + <A href="http://music.example.com/" target="_blank">music.example.com</A> website maintains user sessions with a URL parameter + named session which has the value Vn3IG2FRALSEQX2Nxr at this time for + Jane. The Client will use wrap_client_state to maintain the session + value. The Client redirects Jane's browser to the Authorization + Server's User Authorization URL appending parameters for the Client + Identifier, Callback URL, Client state and authorization scope. +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE><A href="https://auth.example.com/user_authorization?wrap_client_id=music.example.com&wrap_callback=http%3A%2F%2Fmusic.example.com%2Fauth_callback&wrap_client_state=Vn3IG2FRALSEQX2Nxr&wrap_scope=status_update" target="_blank">https://auth.example.com/user_<WBR>authorization?wrap_client_id=<WBR>music.examp +le.com&wrap_callback=http%3A%<WBR>2F%2Fmusic.example.com%2Fauth_<WBR>callback&wr +ap_client_state=<WBR>Vn3IG2FRALSEQX2Nxr&wrap_scope=<WBR>status_update</A> +</PRE></DIV> +<A name="0.2_anchor61"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.B.3"></A><H3>B.3. +Authorization Server Confirms Delegation Request with User</H3> + +<P>The Authorization Server verifies the supplied Client Identifier + <A href="http://music.example.com/" target="_blank">music.example.com</A> has been registered and has the Callback URL + <A href="https://music.example.com/auth_callback" target="_blank">https://music.example.com/<WBR>auth_callback</A>. The Authorization Server + authenticates that the User it is dealing with is Jane, and then asks + Jane to authorize <A href="http://music.example.com/" target="_blank">music.example.com</A> to update Jane's status at + <A href="http://status.example.com/" target="_blank">status.example.com</A>. Jane approves the request and the Authorization + Server generates a Verification Code with the value 46YEXQjVit6T3nQ8, + stores it with the Client Identifier, Callback URl and the current + time. +</P> +<A name="0.2_anchor62"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.B.4"></A><H3>B.4. +Server Directs User back to the Client</H3> + +<P>The Server redirects Jane back to the Client's Callback URL with + the Verification Code and Client State appended: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE><A href="https://music.example.com/auth_callback?wrap_verification_code=46YEXQjVit6T3nQ8&wrap_client_state=Vn3IG2FRALSEQX2Nxr" target="_blank">https://music.example.com/<WBR>auth_callback?wrap_<WBR>verification_code=46YEXQj +Vit6T3nQ8&wrap_client_state=<WBR>Vn3IG2FRALSEQX2Nxr</A> +</PRE></DIV> +<A name="0.2_anchor63"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.B.5"></A><H3>B.5. +Client Requests Access Token</H3> + +<P>The Client makes an HTTPS POST request to: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE><A href="https://auth.example.com/access_token" target="_blank">https://auth.example.com/<WBR>access_token</A> +</PRE></DIV> +<P>With the following message body: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>wrap_client_id=<A href="http://music.example.com/" target="_blank">music.example.<WBR>com</A>&wrap_client_secret=<WBR>7F2986DF2342914A&w +rap_verification_code=<WBR>46YEXQjVit6T3nQ8&wrap_<WBR>callback=http%3A%2F%2Fmusi +<A href="http://c.example.com/" target="_blank">c.example.com</A>%2Fauth_callback +</PRE></DIV> +<A name="0.2_anchor64"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.B.6"></A><H3>B.6. +Successful Access Token Response from Authorization Server</H3> + +<P>The Authorization Server verifies that the Verification Code is + still valid, has not been used, and is associated with the Client ID, + Client Secret and Callback URL Password. The Authorization Server then + generates a Refresh Token with the value: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>MfdWTc+v9MXhpc+d/<WBR>csrKFMPfj1RySm6CzIjmTBGN6w= +</PRE></DIV> +<P>The Authorization Server notes the time is 2010-01-02T03:04:05Z, + which is 1262430245 seconds since 1970-01-01T0:0:0Z. The Authorization + Server then uses the values: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>com.example.auth.scope: status_updatea +com.example.auth.account: Jane +com.example.auth.client: <A href="http://music.example.com/" target="_blank">music.example.com</A> +ExpiresOn: 1262433845 (1262430245 + 3600 seconds later) +Audience: <A href="http://status.example.com/" target="_blank">status.example.com</A> +Issuer: <A href="http://auth.example.com/" target="_blank">auth.example.com</A> +</PRE></DIV> +<P>and the agreed HMAC key to generate the following SWT: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>com.example.auth.scope=status_<WBR>update&com.example.auth.<WBR>account=Jane&com +.example.auth.client=<A href="http://music.example.com/" target="_blank">music.<WBR>example.com</A>&ExpiresOn=<WBR>1262433845&Audience=s +<A href="http://tatus.example.com/" target="_blank">tatus.example.com</A>&Issuer=<A href="http://auth.example.com/" target="_blank">auth.<WBR>example.com</A>&HMACSHA256=<WBR>3xZAYzJRtYCQgkAF3 +iqElp1DhyKkPhq947j04NcDocQ%3D +</PRE></DIV> +<P>The Authorization Server then responds to the Clients HTTPS request + with: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>HTTP 200 OK +</PRE></DIV> +<P>and the Refresh Token, Access Token and lifetime of the Access + Token as application/x-www-form-<WBR>urlencoded data in the body of the + message as such: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>wrap_refresh_token=MfdWTc%<WBR>2Bv9MXhpc%2Bd%<WBR>2FcsrKFMPfj1RySm6CzIjmTBGN6w%3 +D&wrap_access_token=com.<WBR>example.auth.scope%3Dstatus_<WBR>update%26com.examp +le.auth.account%3DJane%26com.<WBR>example.auth.client%<A href="http://3dmusic.example.com/" target="_blank">3Dmusic.<WBR>example.com</A>%2 +6ExpiresOn%3D1262433845%<WBR>26Audience%<A href="http://3dstatus.example.com/" target="_blank">3Dstatus.example.<WBR>com</A>%26Issuer%3Daut +<A href="http://h.example.com/" target="_blank">h.example.com</A>%26HMACSHA256%<WBR>3D3xZAYzJRtYCQgkAF3iqElp1DhyKk<WBR>Phq947j04NcDo +cQ%253D&wrap_access_token_<WBR>expires_in=3600 +</PRE></DIV> +<P>The Client now has a Refresh Token and Access Token valid for an + hour. The Client stores the Refresh Token for later use. +</P> +<A name="0.2_anchor65"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.B.7"></A><H3>B.7. +Client Calls Protected Resource</H3> + +<P>A few minutes later, <A href="http://music.example.com/" target="_blank">music.example.com</A> starts playing a new song + for Jane. The Client updates Jane's status at <A href="http://status.example.com/" target="_blank">status.example.com</A> by + making an API call to: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE><A href="https://status.example.com/update" target="_blank">https://status.example.com/<WBR>update</A> +</PRE></DIV> +<P>including the following HTTP header: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>Authorization: WRAP access_token="com.example.<WBR>auth.scope=status_update +&com.example.auth.account=<WBR>Jane&com.example.auth.client=<WBR>music.example.c +om&ExpiresOn=1262433845&<WBR>Audience=<A href="http://status.example.com/" target="_blank">status.example.com</A>&<WBR>Issuer=auth.exampl +<A href="http://e.com/" target="_blank">e.com</A>&HMACSHA256=<WBR>3xZAYzJRtYCQgkAF3iqElp1DhyKkPh<WBR>q947j04NcDocQ%3D" +</PRE></DIV> +<P>The Protected Resources verifies the SWT, confirms the + authorization contained in the SWT, and updates Jane's status. +</P> +<A name="0.2_anchor66"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<A name="0.2_rfc.section.B.8"></A><H3>B.8. +Client Refreshes Access Token</H3> + +<P>An hour passes by and <A href="http://music.example.com/" target="_blank">music.example.com</A> starts playing another new + song for Jane. The Client again makes an API call to + <A href="http://status.example.com/" target="_blank">status.example.com</A> including the same HTTP Authorization header. + Unlike previous calls where the status update was performed, the + Protected Resource returns the following error response: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>HTTP 401 Unauthorized +</PRE></DIV> +<P>and the HTTP header: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>WWW-Authenticate: WRAP +</PRE></DIV> +<P>The Client determines it probably needs a new Access Token, + retrieves the Refresh Token and makes an HTTPS POST to: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE><A href="https://auth.example.com/refresh_token" target="_blank">https://auth.example.com/<WBR>refresh_token</A> +</PRE></DIV> +<P>including the Client Identifier, Client Secret and Refresh Token in + the message body as: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>wrap_client_id=<A href="http://music.example.com/" target="_blank">music.example.<WBR>com</A>&wrap_client_secret=<WBR>7F2986DF2342914A&w +rap_refresh_token=MfdWTc%<WBR>2Bv9MXhpc%2Bd%<WBR>2FcsrKFMPfj1RySm6CzIjmTBGN6w%<WBR>3D +</PRE></DIV> +<P>The Authorization Server looks up the data associated with the + Refresh Token, determines <A href="http://music.example.com/" target="_blank">music.example.com</A> is still authorized to + update Jane's status, and determines it will generate a new Access + Token for the Client that expires in an hour. The time is now + 2010-01-02T04:15:23Z, which results in an Access Token expiry time of + 1262438123 seconds since 1970-01-01T0:0:0Z. The Authorization Server + generates a new Access Token and returns it in the body of the message + as: +</P><DIV style="display:table;width:0;margin-left:3em;margin-right:auto"><PRE>wrap_access_token=com.example.<WBR>auth.scope=status_update&com.<WBR>example.aut +h.account=Jane&com.example.<WBR>auth.client=<A href="http://music.example.com/" target="_blank">music.example.com</A>&<WBR>ExpiresOn=126 +2438123&Audience=<A href="http://status.example.com/" target="_blank">status.<WBR>example.com</A>&Issuer=<A href="http://auth.example.com/" target="_blank">auth.<WBR>example.com</A>&HMACSHA256 +=<WBR>AT4TFChHgyylItEWAjK7MFRJuvUS3W<WBR>LVzO%2F68gvIRQI%3D&wrap_<WBR>access_token_ex +pires_in=3600 +</PRE></DIV> +<P>The Client takes the new Access Token and uses it to successfully + update Jane's status at <A href="http://status.example.com/" target="_blank">status.example.com</A>. +</P> +<A name="0.2_rfc.authors"></A><BR><HR> +<TABLE summary="layout" cellpadding="0" cellspacing="2" align="right"><TBODY><TR><TD><A href="https://mail.google.com/mail/?ui=2&ik=c5d0d94d4a&view=att&th=12634202598d2cea&attid=0.2&disp=inline&realattid=f_g4hjnq761&zw#0.2_toc"> TOC </A></TD></TR></TBODY></TABLE> +<H3>Authors' Addresses</H3> +<TABLE width="99%" border="0" cellpadding="0" cellspacing="0"> +<TBODY><TR><TD> </TD> +<TD>Dick Hardt (editor)</TD></TR> +<TR><TD> </TD> +<TD>Microsoft</TD></TR> +<TR><TD align="right">Email: </TD> +<TD><A href="mailto:dick.hardt@gmail.com" target="_blank">dick.hardt@gmail.com</A></TD></TR> +<TR cellpadding="3"><TD> </TD><TD> </TD></TR> +<TR><TD> </TD> +<TD>Allen Tom</TD></TR> +<TR><TD> </TD> +<TD>Yahoo!</TD></TR> +<TR><TD align="right">Email: </TD> +<TD><A href="mailto:atom@yahoo-inc.com" target="_blank">atom@yahoo-inc.com</A></TD></TR> +<TR cellpadding="3"><TD> </TD><TD> </TD></TR> +<TR><TD> </TD> +<TD>Brian Eaton</TD></TR> +<TR><TD> </TD> +<TD>Google</TD></TR> +<TR><TD align="right">Email: </TD> +<TD><A href="mailto:beaton@google.com" target="_blank">beaton@google.com</A></TD></TR> +<TR cellpadding="3"><TD> </TD><TD> </TD></TR> +<TR><TD> </TD> +<TD>Yaron Goland</TD></TR> +<TR><TD> </TD> +<TD>Microsoft</TD></TR> +<TR><TD align="right">Email: </TD> +<TD><A href="mailto:yarong@microsoft.com" target="_blank">yarong@microsoft.com</A></TD></TR> +</TBODY></TABLE> +</DIV> + +</BODY></HTML>
\ No newline at end of file diff --git a/src/DotNetOpenAuth.Test/Mocks/TestDirectResponseMessageWithHttpStatus.cs b/src/DotNetOpenAuth.Test/Mocks/TestDirectResponseMessageWithHttpStatus.cs index d692320..20fd6c4 100644 --- a/src/DotNetOpenAuth.Test/Mocks/TestDirectResponseMessageWithHttpStatus.cs +++ b/src/DotNetOpenAuth.Test/Mocks/TestDirectResponseMessageWithHttpStatus.cs @@ -8,6 +8,7 @@ namespace DotNetOpenAuth.Test.Mocks { using System; using System.Collections.Generic; using System.Linq; + using System.Net; using System.Text; using DotNetOpenAuth.Messaging; @@ -23,8 +24,15 @@ namespace DotNetOpenAuth.Test.Mocks { /// <summary> /// Gets or sets the HTTP status code that the direct respones should be sent with. /// </summary> - /// <value></value> - public System.Net.HttpStatusCode HttpStatusCode { get; set; } + public HttpStatusCode HttpStatusCode { get; set; } + + /// <summary> + /// Gets the HTTP headers to add to the response. + /// </summary> + /// <value>May be an empty collection, but must not be <c>null</c>.</value> + public WebHeaderCollection Headers { + get { return new WebHeaderCollection(); } + } #endregion } diff --git a/src/DotNetOpenAuth.sln b/src/DotNetOpenAuth.sln index 55d43e8..135d51f 100644 --- a/src/DotNetOpenAuth.sln +++ b/src/DotNetOpenAuth.sln @@ -13,6 +13,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Specs", "Specs", "{CD57219F-24F4-4136-8741-6063D0D7A031}" ProjectSection(SolutionItems) = preProject + ..\doc\specs\draft-hardt-oauth-01.htm = ..\doc\specs\draft-hardt-oauth-01.htm ..\doc\specs\ICAM_OpenID20Profile.pdf = ..\doc\specs\ICAM_OpenID20Profile.pdf ..\doc\specs\OAuth Core 1.0.htm = ..\doc\specs\OAuth Core 1.0.htm ..\doc\specs\OAuth Core 1.0a (Draft 3).htm = ..\doc\specs\OAuth Core 1.0a (Draft 3).htm diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj index 80487fc..7f5b298 100644 --- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj +++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj @@ -224,13 +224,13 @@ http://opensource.org/licenses/ms-pl.html </Reference> </ItemGroup> <ItemGroup Condition=" '$(ClrVersion)' == '4' "> - <Reference Include="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"/> + <Reference Include="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" /> </ItemGroup> <ItemGroup Condition=" '$(ClrVersion)' != '4' "> <!-- MVC 2 can run on CLR 2 (it doesn't require CLR 4) but since MVC 2 apps tend to use type forwarding, it's a more broadly consumable idea to bind against MVC 1 for the library unless we're building on CLR 4, which will definitely have MVC 2 available. --> - <Reference Include="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"/> + <Reference Include="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" /> </ItemGroup> <ItemGroup> <Compile Include="ComponentModel\ClaimTypeSuggestions.cs" /> @@ -284,6 +284,7 @@ http://opensource.org/licenses/ms-pl.html <Compile Include="Messaging\HostErrorException.cs" /> <Compile Include="Messaging\IHttpDirectResponse.cs" /> <Compile Include="Messaging\IExtensionMessage.cs" /> + <Compile Include="Messaging\IHttpDirectResponseContract.cs" /> <Compile Include="Messaging\IMessage.cs" /> <Compile Include="Messaging\IncomingWebResponse.cs" /> <Compile Include="Messaging\IDirectResponseProtocolMessage.cs" /> @@ -302,6 +303,28 @@ http://opensource.org/licenses/ms-pl.html <Compile Include="Messaging\Reflection\IMessagePartEncoder.cs" /> <Compile Include="Messaging\Reflection\IMessagePartNullEncoder.cs" /> <Compile Include="Messaging\Reflection\MessageDescriptionCollection.cs" /> + <Compile Include="OAuthWrap\IClientTokenManager.cs" /> + <Compile Include="OAuthWrap\Messages\Assertion\AssertionRequest.cs" /> + <Compile Include="OAuthWrap\Messages\Assertion\AssertionFailedResponse.cs" /> + <Compile Include="OAuthWrap\Messages\ClientAccountAndPassword\ClientAccountUsernamePasswordFailedResponse.cs" /> + <Compile Include="OAuthWrap\Messages\ClientAccountAndPassword\ClientAccountUsernamePasswordRequest.cs" /> + <Compile Include="OAuthWrap\Messages\ClientAccountAndPassword\ClientAccountUsernamePasswordSuccessResponse.cs" /> + <Compile Include="OAuthWrap\Messages\Assertion\AssertionSuccessResponse.cs" /> + <Compile Include="OAuthWrap\Messages\IMessageWithClientState.cs" /> + <Compile Include="OAuthWrap\Messages\RichApp\RichAppAccessTokenRequest.cs" /> + <Compile Include="OAuthWrap\Messages\RichApp\RichAppRequest.cs" /> + <Compile Include="OAuthWrap\Messages\RichApp\RichAppResponse.cs" /> + <Compile Include="OAuthWrap\Messages\RichApp\RichAppAccessTokenSuccessResponse.cs" /> + <Compile Include="OAuthWrap\Messages\RichApp\RichAppAccessTokenFailedResponse.cs" /> + <Compile Include="OAuthWrap\Messages\UnauthorizedResponse.cs" /> + <Compile Include="OAuthWrap\Messages\RefreshAccessTokenFailedResponse.cs" /> + <Compile Include="OAuthWrap\Messages\RefreshAccessTokenSuccessResponse.cs" /> + <Compile Include="OAuthWrap\Messages\RefreshAccessTokenRequest.cs" /> + <Compile Include="OAuthWrap\Messages\UsernameAndPassword\UserNamePasswordCaptchaResponse.cs" /> + <Compile Include="OAuthWrap\Messages\UsernameAndPassword\UserNamePasswordVerificationResponse.cs" /> + <Compile Include="OAuthWrap\Messages\WebApp\WebAppAccessTokenBadClientResponse.cs" /> + <Compile Include="OAuthWrap\Messages\WebApp\WebAppAccessTokenFailedResponse.cs" /> + <Compile Include="OAuthWrap\WrapUtilities.cs" /> <Compile Include="OAuth\ChannelElements\ICombinedOpenIdProviderTokenManager.cs" /> <Compile Include="OAuth\ChannelElements\IConsumerDescription.cs" /> <Compile Include="OAuth\ChannelElements\IConsumerTokenManager.cs" /> @@ -445,7 +468,7 @@ http://opensource.org/licenses/ms-pl.html <Compile Include="OpenId\Extensions\ProviderAuthenticationPolicy\PapeUtilities.cs" /> <Compile Include="OpenId\Extensions\ProviderAuthenticationPolicy\PolicyRequest.cs" /> <Compile Include="OpenId\Extensions\ProviderAuthenticationPolicy\PolicyResponse.cs" /> - <Compile Include="OpenId\Extensions\ProviderAuthenticationPolicy\TimespanSecondsEncoder.cs" /> + <Compile Include="Messaging\TimespanSecondsEncoder.cs" /> <Compile Include="OpenId\Extensions\SimpleRegistration\ClaimsRequest.cs" /> <Compile Include="OpenId\Extensions\SimpleRegistration\ClaimsResponse.cs" /> <Compile Include="OpenId\Extensions\SimpleRegistration\Constants.cs" /> @@ -586,6 +609,26 @@ http://opensource.org/licenses/ms-pl.html <Compile Include="Messaging\StandardWebRequestHandler.cs" /> <Compile Include="Messaging\MessageReceivingEndpoint.cs" /> <Compile Include="Reporting.cs" /> + <Compile Include="OAuthWrap\ChannelElements\OAuthWrapChannel.cs" /> + <Compile Include="OAuthWrap\ChannelElements\OAuthWrapMessageFactory.cs" /> + <Compile Include="OAuthWrap\ClientBase.cs" /> + <Compile Include="OAuthWrap\Messages\WebApp\WebAppAccessTokenSuccessResponse.cs" /> + <Compile Include="OAuthWrap\Messages\MessageBase.cs" /> + <Compile Include="OAuthWrap\Messages\WebApp\WebAppAccessTokenRequest.cs" /> + <Compile Include="OAuthWrap\Messages\WebApp\WebAppFailedResponse.cs" /> + <Compile Include="OAuthWrap\Messages\WebApp\WebAppRequest.cs" /> + <Compile Include="OAuthWrap\Messages\WebApp\WebAppSuccessResponse.cs" /> + <Compile Include="OAuthWrap\Messages\UsernameAndPassword\UserNamePasswordFailedResponse.cs" /> + <Compile Include="OAuthWrap\Messages\UsernameAndPassword\UserNamePasswordRequest.cs" /> + <Compile Include="OAuthWrap\Messages\UsernameAndPassword\UserNamePasswordSuccessResponse.cs" /> + <Compile Include="OAuthWrap\Protocol.cs" /> + <Compile Include="OAuthWrap\OAuthWrapStrings.Designer.cs"> + <AutoGen>True</AutoGen> + <DesignTime>True</DesignTime> + <DependentUpon>OAuthWrapStrings.resx</DependentUpon> + </Compile> + <Compile Include="OAuthWrap\AuthorizationServerDescription.cs" /> + <Compile Include="OAuthWrap\WebAppClient.cs" /> <Compile Include="Util.cs" /> <Compile Include="OAuth\Protocol.cs" /> <Compile Include="OAuth\ServiceProvider.cs" /> @@ -698,6 +741,10 @@ http://opensource.org/licenses/ms-pl.html <EmbeddedResource Include="OpenId\RelyingParty\OpenIdRelyingPartyAjaxControlBase.js"> <Copyright>$(StandardCopyright)</Copyright> </EmbeddedResource> + <EmbeddedResource Include="OAuthWrap\OAuthWrapStrings.resx"> + <Generator>ResXFileCodeGenerator</Generator> + <LastGenOutput>OAuthWrapStrings.Designer.cs</LastGenOutput> + </EmbeddedResource> <EmbeddedResource Include="Strings.sr.resx" /> <EmbeddedResource Include="Xrds\XrdsStrings.sr.resx" /> </ItemGroup> diff --git a/src/DotNetOpenAuth/Messaging/IHttpDirectResponse.cs b/src/DotNetOpenAuth/Messaging/IHttpDirectResponse.cs index c0e7803..20c3d6f 100644 --- a/src/DotNetOpenAuth/Messaging/IHttpDirectResponse.cs +++ b/src/DotNetOpenAuth/Messaging/IHttpDirectResponse.cs @@ -5,16 +5,24 @@ //----------------------------------------------------------------------- namespace DotNetOpenAuth.Messaging { + using System.Diagnostics.Contracts; using System.Net; /// <summary> /// An interface that allows direct response messages to specify /// HTTP transport specific properties. /// </summary> + [ContractClass(typeof(IHttpDirectResponseContract))] public interface IHttpDirectResponse { /// <summary> - /// Gets the HTTP status code that the direct respones should be sent with. + /// Gets the HTTP status code that the direct response should be sent with. /// </summary> HttpStatusCode HttpStatusCode { get; } + + /// <summary> + /// Gets the HTTP headers to add to the response. + /// </summary> + /// <value>May be an empty collection, but must not be <c>null</c>.</value> + WebHeaderCollection Headers { get; } } } diff --git a/src/DotNetOpenAuth/Messaging/IHttpDirectResponseContract.cs b/src/DotNetOpenAuth/Messaging/IHttpDirectResponseContract.cs new file mode 100644 index 0000000..b1ddba2 --- /dev/null +++ b/src/DotNetOpenAuth/Messaging/IHttpDirectResponseContract.cs @@ -0,0 +1,43 @@ +//----------------------------------------------------------------------- +// <copyright file="IHttpDirectResponseContract.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Messaging { + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + using System.Linq; + using System.Net; + using System.Text; + + /// <summary> + /// Contract class for the <see cref="IHttpDirectResponse"/> interface. + /// </summary> + [ContractClassFor(typeof(IHttpDirectResponse))] + public abstract class IHttpDirectResponseContract : IHttpDirectResponse { + #region IHttpDirectResponse Members + + /// <summary> + /// Gets the HTTP status code that the direct response should be sent with. + /// </summary> + /// <value></value> + HttpStatusCode IHttpDirectResponse.HttpStatusCode { + get { throw new NotImplementedException(); } + } + + /// <summary> + /// Gets the HTTP headers to add to the response. + /// </summary> + /// <value>May be an empty collection, but must not be <c>null</c>.</value> + WebHeaderCollection IHttpDirectResponse.Headers { + get { + Contract.Ensures(Contract.Result<WebHeaderCollection>() != null); + throw new NotImplementedException(); + } + } + + #endregion + } +} diff --git a/src/DotNetOpenAuth/OpenId/Extensions/ProviderAuthenticationPolicy/TimespanSecondsEncoder.cs b/src/DotNetOpenAuth/Messaging/TimespanSecondsEncoder.cs index cc3f7cc..3ad1bd8 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/ProviderAuthenticationPolicy/TimespanSecondsEncoder.cs +++ b/src/DotNetOpenAuth/Messaging/TimespanSecondsEncoder.cs @@ -4,7 +4,7 @@ // </copyright> //----------------------------------------------------------------------- -namespace DotNetOpenAuth.OpenId.Extensions.ProviderAuthenticationPolicy { +namespace DotNetOpenAuth.Messaging { using System; using System.Globalization; using DotNetOpenAuth.Messaging.Reflection; @@ -13,6 +13,12 @@ namespace DotNetOpenAuth.OpenId.Extensions.ProviderAuthenticationPolicy { /// Encodes and decodes the <see cref="TimeSpan"/> as an integer of total seconds. /// </summary> internal class TimespanSecondsEncoder : IMessagePartEncoder { + /// <summary> + /// Initializes a new instance of the <see cref="TimespanSecondsEncoder"/> class. + /// </summary> + internal TimespanSecondsEncoder() { + } + #region IMessagePartEncoder Members /// <summary> diff --git a/src/DotNetOpenAuth/OAuth/Protocol.cs b/src/DotNetOpenAuth/OAuth/Protocol.cs index a524ba7..71a25f8 100644 --- a/src/DotNetOpenAuth/OAuth/Protocol.cs +++ b/src/DotNetOpenAuth/OAuth/Protocol.cs @@ -100,7 +100,7 @@ namespace DotNetOpenAuth.OAuth { } /// <summary> - /// Gets the version used to represent OAuth 1.0a. + /// Gets the OAuth version this instance represents. /// </summary> internal Version Version { get; private set; } diff --git a/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerDescription.cs b/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerDescription.cs new file mode 100644 index 0000000..c04cec0 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerDescription.cs @@ -0,0 +1,64 @@ +//----------------------------------------------------------------------- +// <copyright file="AuthorizationServerDescription.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + + /// <summary> + /// A description of an OAuth WRAP Authorization Server. + /// </summary> + public class AuthorizationServerDescription { + /// <summary> + /// Initializes a new instance of the <see cref="AuthorizationServerDescription"/> class. + /// </summary> + public AuthorizationServerDescription() { + this.ProtocolVersion = Protocol.Default.ProtocolVersion; + } + + /// <summary> + /// Gets or sets the Authorization Server URL at which an Access Token is requested by the Client. + /// A refresh token may also be returned to the Client. + /// </summary> + /// <value>An HTTPS URL.</value> + /// <remarks> + /// Messages sent to this URL must always be sent by the POST HTTP method. + /// </remarks> + public Uri AccessTokenEndpoint { get; set; } + + /// <summary> + /// Gets or sets the Authorization Server URL at which a Refresh Token is presented in exchange + /// for a new Access Token. + /// </summary> + /// <value>An HTTPS URL.</value> + /// <remarks> + /// Messages sent to this URL must always be sent by the POST HTTP method. + /// </remarks> + public Uri RefreshTokenEndpoint { get; set; } + + /// <summary> + /// Gets or sets the Authorization Server URL where the Client (re)directs the User + /// to make an authorization request. + /// </summary> + /// <value>An HTTP or HTTPS URL.</value> + public Uri UserAuthorizationEndpoint { get; set; } + + /// <summary> + /// Gets or sets the OAuth WRAP version supported by the Authorization Server. + /// </summary> + public ProtocolVersion ProtocolVersion { get; set; } + + /// <summary> + /// Gets the version of the OAuth WRAP protocol to use with this Authorization Server. + /// </summary> + /// <value>The version.</value> + internal Version Version { + get { return Protocol.Lookup(this.ProtocolVersion).Version; } + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapChannel.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapChannel.cs new file mode 100644 index 0000000..3c2065f --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapChannel.cs @@ -0,0 +1,52 @@ +//----------------------------------------------------------------------- +// <copyright file="OAuthWrapChannel.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.ChannelElements { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// The channel for the OAuth WRAP protocol. + /// </summary> + internal class OAuthWrapChannel : Channel { + /// <summary> + /// Initializes a new instance of the <see cref="OAuthWrapChannel"/> class. + /// </summary> + internal OAuthWrapChannel() + : base(new OAuthWrapMessageFactory()) { + } + + /// <summary> + /// Gets the protocol message that may be in the given HTTP response. + /// </summary> + /// <param name="response">The response that is anticipated to contain an protocol message.</param> + /// <returns> + /// The deserialized message parts, if found. Null otherwise. + /// </returns> + /// <exception cref="ProtocolException">Thrown when the response is not valid.</exception> + protected override IDictionary<string, string> ReadFromResponseCore(IncomingWebResponse response) { + throw new NotImplementedException(); + } + + /// <summary> + /// Queues a message for sending in the response stream where the fields + /// are sent in the response stream in querystring style. + /// </summary> + /// <param name="response">The message to send as a response.</param> + /// <returns> + /// The pending user agent redirect based message to be sent as an HttpResponse. + /// </returns> + /// <remarks> + /// This method implements spec OAuth V1.0 section 5.3. + /// </remarks> + protected override OutgoingWebResponse PrepareDirectResponse(IProtocolMessage response) { + throw new NotImplementedException(); + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapMessageFactory.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapMessageFactory.cs new file mode 100644 index 0000000..b3b9abb --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapMessageFactory.cs @@ -0,0 +1,99 @@ +//----------------------------------------------------------------------- +// <copyright file="OAuthWrapMessageFactory.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.ChannelElements { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuthWrap.Messages; + + /// <summary> + /// The message factory for OAuth WRAP messages. + /// </summary> + internal class OAuthWrapMessageFactory : IMessageFactory { + /// <summary> + /// Initializes a new instance of the <see cref="OAuthWrapMessageFactory"/> class. + /// </summary> + internal OAuthWrapMessageFactory() { + } + + #region IMessageFactory Members + + /// <summary> + /// Analyzes an incoming request message payload to discover what kind of + /// message is embedded in it and returns the type, or null if no match is found. + /// </summary> + /// <param name="recipient">The intended or actual recipient of the request message.</param> + /// <param name="fields">The name/value pairs that make up the message payload.</param> + /// <returns> + /// A newly instantiated <see cref="IProtocolMessage"/>-derived object that this message can + /// deserialize to. Null if the request isn't recognized as a valid protocol message. + /// </returns> + public IDirectedProtocolMessage GetNewRequestMessage(MessageReceivingEndpoint recipient, IDictionary<string, string> fields) { + Version version = Protocol.DefaultVersion; + + if (fields.ContainsKey(Protocol.wrap_client_id) && fields.ContainsKey(Protocol.wrap_callback)) { + return new WebAppRequest(recipient.Location, version); + } + + if (fields.ContainsKey(Protocol.wrap_client_id) && fields.ContainsKey(Protocol.wrap_verification_code)) { + return new WebAppAccessTokenRequest(recipient.Location, version); + } + + if (fields.ContainsKey(Protocol.wrap_name)) { + return new ClientAccountUsernamePasswordRequest(recipient.Location, version); + } + + if (fields.ContainsKey(Protocol.wrap_username)) { + return new UserNamePasswordRequest(recipient.Location, version); + } + + if (fields.ContainsKey(Protocol.wrap_verification_code)) { + return new WebAppSuccessResponse(recipient.Location, version); + } + + return null; + } + + /// <summary> + /// Analyzes an incoming request message payload to discover what kind of + /// message is embedded in it and returns the type, or null if no match is found. + /// </summary> + /// <param name="request">The message that was sent as a request that resulted in the response.</param> + /// <param name="fields">The name/value pairs that make up the message payload.</param> + /// <returns> + /// A newly instantiated <see cref="IProtocolMessage"/>-derived object that this message can + /// deserialize to. Null if the request isn't recognized as a valid protocol message. + /// </returns> + public IDirectResponseProtocolMessage GetNewResponseMessage(IDirectedProtocolMessage request, IDictionary<string, string> fields) { + Version version = Protocol.DefaultVersion; + + var accessTokenRequest = request as WebAppAccessTokenRequest; + if (accessTokenRequest != null) { + if (fields.ContainsKey(Protocol.wrap_access_token)) { + return new WebAppAccessTokenSuccessResponse(accessTokenRequest); + } else { + //return new AccessTokenWithVerificationCodeFailedResponse(accessTokenRequest); + } + } + + var userAuthorization = request as UserNamePasswordRequest; + if (userAuthorization != null) { + if (fields.ContainsKey(Protocol.wrap_verification_code)) { + return new UserNamePasswordSuccessResponse(userAuthorization); + } else { + //return new UserAuthorizationViaUsernamePasswordFailedResponse(userAuthorization); + } + } + + return null; + } + + #endregion + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/ClientBase.cs b/src/DotNetOpenAuth/OAuthWrap/ClientBase.cs new file mode 100644 index 0000000..a36759d --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/ClientBase.cs @@ -0,0 +1,54 @@ +//----------------------------------------------------------------------- +// <copyright file="ClientBase.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap { + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + using System.Globalization; + using System.Linq; + using System.Net; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A base class for common OAuth WRAP Consumer behaviors. + /// </summary> + public class ClientBase { + /// <summary> + /// Initializes a new instance of the <see cref="ClientBase"/> class. + /// </summary> + /// <param name="authorizationServer">The token issuer.</param> + protected ClientBase(AuthorizationServerDescription authorizationServer) { + Contract.Requires<ArgumentNullException>(authorizationServer != null); + this.AuthorizationServer = authorizationServer; + } + + /// <summary> + /// Gets the token issuer. + /// </summary> + /// <value>The token issuer.</value> + public AuthorizationServerDescription AuthorizationServer { get; private set; } + + /// <summary> + /// Gets the OAuth WRAP channel. + /// </summary> + /// <value>The channel.</value> + public Channel Channel { get; private set; } + + /// <summary> + /// Adds the necessary HTTP Authorization header to an HTTP request for protected resources + /// so that the Service Provider will allow the request through. + /// </summary> + /// <param name="request">The request for protected resources from the service provider.</param> + /// <param name="accessToken">The access token previously obtained from the Authorization Server.</param> + public static void AuthorizeRequest(HttpWebRequest request, string accessToken) { + Contract.Requires<ArgumentNullException>(request != null); + Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(accessToken)); + WrapUtilities.AuthorizeWithOAuthWrap(request, accessToken); + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/IClientTokenManager.cs b/src/DotNetOpenAuth/OAuthWrap/IClientTokenManager.cs new file mode 100644 index 0000000..4cedaee --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/IClientTokenManager.cs @@ -0,0 +1,43 @@ +//----------------------------------------------------------------------- +// <copyright file="IClientTokenManager.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; +using System.Diagnostics.Contracts; + + [ContractClass(typeof(IClientTokenManagerContract))] + public interface IClientTokenManager { + IWrapAuthorization GetAuthorizationState(Uri callbackUrl, string clientState); + } + + internal class IClientTokenManagerContract : IClientTokenManager { + private IClientTokenManagerContract() { + } + + #region IClientTokenManager Members + + IWrapAuthorization IClientTokenManager.GetAuthorizationState(Uri callbackUrl, string clientState) { + Contract.Requires<ArgumentNullException>(callbackUrl != null); + throw new NotImplementedException(); + } + + #endregion + } + + + public interface IWrapAuthorization { + Uri Callback { get; set; } + string RefreshToken { get; set; } + string AccessToken { get; set; } + DateTime? AccessTokenExpirationUtc { get; set; } + string Scope { get; set; } + + void Delete(); + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/Assertion/AssertionFailedResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/Assertion/AssertionFailedResponse.cs new file mode 100644 index 0000000..020192e --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/Assertion/AssertionFailedResponse.cs @@ -0,0 +1,21 @@ +//----------------------------------------------------------------------- +// <copyright file="AssertionFailedResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + /// <summary> + /// A response from the Authorization Server to the Client to indicate that a + /// request for an access code failed, probably due to an invalid assertion. + /// </summary> + internal class AssertionFailedResponse : UnauthorizedResponse { + /// <summary> + /// Initializes a new instance of the <see cref="AssertionFailedResponse"/> class. + /// </summary> + /// <param name="request">The request.</param> + internal AssertionFailedResponse(AssertionRequest request) + : base(request) { + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/Assertion/AssertionRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/Assertion/AssertionRequest.cs new file mode 100644 index 0000000..cfd537a --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/Assertion/AssertionRequest.cs @@ -0,0 +1,65 @@ +//----------------------------------------------------------------------- +// <copyright file="AssertionRequest.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A request from a Client to an Authorization Server with some assertion for an access token. + /// </summary> + internal class AssertionRequest : MessageBase { + /// <summary> + /// Initializes a new instance of the <see cref="AssertionRequest"/> class. + /// </summary> + /// <param name="version">The version.</param> + /// <param name="authorizationServer">The authorization server.</param> + internal AssertionRequest(Version version, Uri authorizationServer) + : base(version, MessageTransport.Direct, authorizationServer) { + this.HttpMethods = HttpDeliveryMethods.PostRequest; + } + + /// <summary> + /// Gets or sets the format of the assertion as defined by the Authorization Server. + /// </summary> + /// <value>The assertion format.</value> + [MessagePart(Protocol.wrap_assertion_format, IsRequired = true, AllowEmpty = false)] + internal string AssertionFormat { get; set; } + + /// <summary> + /// Gets or sets the assertion. + /// </summary> + /// <value>The assertion.</value> + [MessagePart(Protocol.wrap_assertion, IsRequired = true, AllowEmpty = false)] + internal string Assertion { get; set; } + + /// <summary> + /// Gets or sets an optional authorization scope as defined by the Authorization Server. + /// </summary> + [MessagePart(Protocol.wrap_scope, IsRequired = false, AllowEmpty = true)] + internal string Scope { get; set; } + + /// <summary> + /// Checks the message state for conformity to the protocol specification + /// and throws an exception if the message is invalid. + /// </summary> + /// <remarks> + /// <para>Some messages have required fields, or combinations of fields that must relate to each other + /// in specialized ways. After deserializing a message, this method checks the state of the + /// message to see if it conforms to the protocol.</para> + /// <para>Note that this property should <i>not</i> check signatures or perform any state checks + /// outside this scope of this particular message.</para> + /// </remarks> + /// <exception cref="ProtocolException">Thrown if the message is invalid.</exception> + protected override void EnsureValidMessage() { + base.EnsureValidMessage(); + ErrorUtilities.VerifyProtocol(this.Recipient.IsTransportSecure(), OAuthWrapStrings.HttpsRequired); + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/Assertion/AssertionSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/Assertion/AssertionSuccessResponse.cs new file mode 100644 index 0000000..a934c07 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/Assertion/AssertionSuccessResponse.cs @@ -0,0 +1,40 @@ +//----------------------------------------------------------------------- +// <copyright file="AssertionSuccessResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A response from the Authorization Server to the Client containing an access code. + /// </summary> + internal class AssertionSuccessResponse : MessageBase { + /// <summary> + /// Initializes a new instance of the <see cref="AssertionSuccessResponse"/> class. + /// </summary> + /// <param name="request">The request.</param> + internal AssertionSuccessResponse(ClientAccountUsernamePasswordRequest request) + : base(request) { + } + + /// <summary> + /// Gets or sets the access token. + /// </summary> + /// <value>The access token.</value> + [MessagePart(Protocol.wrap_access_token, IsRequired = true, AllowEmpty = false)] + internal string AccessToken { get; set; } + + /// <summary> + /// Gets or sets the lifetime of the access token. + /// </summary> + /// <value>The lifetime.</value> + [MessagePart(Protocol.wrap_access_token_expires_in, IsRequired = false, Encoder = typeof(TimespanSecondsEncoder))] + internal TimeSpan Lifetime { get; set; } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/ClientAccountAndPassword/ClientAccountUsernamePasswordFailedResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/ClientAccountAndPassword/ClientAccountUsernamePasswordFailedResponse.cs new file mode 100644 index 0000000..57ce588 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/ClientAccountAndPassword/ClientAccountUsernamePasswordFailedResponse.cs @@ -0,0 +1,22 @@ +//----------------------------------------------------------------------- +// <copyright file="ClientAccountUsernamePasswordFailedResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + /// <summary> + /// A response from the Authorization Server to the Client to indicate that a + /// request for an access code failed, probably due to an invalid account + /// name and password. + /// </summary> + internal class ClientAccountUsernamePasswordFailedResponse : UnauthorizedResponse { + /// <summary> + /// Initializes a new instance of the <see cref="ClientAccountUsernamePasswordFailedResponse"/> class. + /// </summary> + /// <param name="request">The request.</param> + internal ClientAccountUsernamePasswordFailedResponse(ClientAccountUsernamePasswordRequest request) + : base(request) { + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/ClientAccountAndPassword/ClientAccountUsernamePasswordRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/ClientAccountAndPassword/ClientAccountUsernamePasswordRequest.cs new file mode 100644 index 0000000..9f47c57 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/ClientAccountAndPassword/ClientAccountUsernamePasswordRequest.cs @@ -0,0 +1,69 @@ +//----------------------------------------------------------------------- +// <copyright file="ClientAccountUsernamePasswordRequest.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A request for an access token for a client application that has its + /// own (non-user affiliated) client name and password. + /// </summary> + /// <remarks> + /// This is somewhat analogous to 2-legged OAuth. + /// </remarks> + internal class ClientAccountUsernamePasswordRequest : MessageBase { + /// <summary> + /// Initializes a new instance of the <see cref="ClientAccountUsernamePasswordRequest"/> class. + /// </summary> + /// <param name="authorizationServer">The authorization server.</param> + /// <param name="version">The version.</param> + internal ClientAccountUsernamePasswordRequest(Uri authorizationServer, Version version) + : base(version, MessageTransport.Direct, authorizationServer) { + this.HttpMethods = HttpDeliveryMethods.PostRequest; + } + + /// <summary> + /// Gets or sets the account name. + /// </summary> + /// <value>The name on the account.</value> + [MessagePart(Protocol.wrap_name, IsRequired = true, AllowEmpty = false)] + internal string Name { get; set; } + + /// <summary> + /// Gets or sets the user's password. + /// </summary> + /// <value>The password.</value> + [MessagePart(Protocol.wrap_password, IsRequired = true, AllowEmpty = false)] + internal string Password { get; set; } + + /// <summary> + /// Gets or sets an optional authorization scope as defined by the Authorization Server. + /// </summary> + [MessagePart(Protocol.wrap_scope, IsRequired = false, AllowEmpty = true)] + internal string Scope { get; set; } + + /// <summary> + /// Checks the message state for conformity to the protocol specification + /// and throws an exception if the message is invalid. + /// </summary> + /// <remarks> + /// <para>Some messages have required fields, or combinations of fields that must relate to each other + /// in specialized ways. After deserializing a message, this method checks the state of the + /// message to see if it conforms to the protocol.</para> + /// <para>Note that this property should <i>not</i> check signatures or perform any state checks + /// outside this scope of this particular message.</para> + /// </remarks> + /// <exception cref="ProtocolException">Thrown if the message is invalid.</exception> + protected override void EnsureValidMessage() { + base.EnsureValidMessage(); + ErrorUtilities.VerifyProtocol(this.Recipient.IsTransportSecure(), OAuthWrapStrings.HttpsRequired); + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/ClientAccountAndPassword/ClientAccountUsernamePasswordSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/ClientAccountAndPassword/ClientAccountUsernamePasswordSuccessResponse.cs new file mode 100644 index 0000000..186827c --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/ClientAccountAndPassword/ClientAccountUsernamePasswordSuccessResponse.cs @@ -0,0 +1,47 @@ +//----------------------------------------------------------------------- +// <copyright file="ClientAccountUsernamePasswordSuccessResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A response from the Authorization Server to the Client containing an access code. + /// </summary> + internal class ClientAccountUsernamePasswordSuccessResponse : MessageBase { + /// <summary> + /// Initializes a new instance of the <see cref="ClientAccountUsernamePasswordSuccessResponse"/> class. + /// </summary> + /// <param name="request">The request.</param> + internal ClientAccountUsernamePasswordSuccessResponse(ClientAccountUsernamePasswordRequest request) + : base(request) { + } + + /// <summary> + /// Gets or sets the refresh token. + /// </summary> + /// <value>The token.</value> + [MessagePart(Protocol.wrap_refresh_token, IsRequired = true, AllowEmpty = false)] + internal string RefreshToken { get; set; } + + /// <summary> + /// Gets or sets the access token. + /// </summary> + /// <value>The access token.</value> + [MessagePart(Protocol.wrap_access_token, IsRequired = true, AllowEmpty = false)] + internal string AccessToken { get; set; } + + /// <summary> + /// Gets or sets the lifetime of the access token. + /// </summary> + /// <value>The lifetime.</value> + [MessagePart(Protocol.wrap_access_token_expires_in, IsRequired = false, Encoder = typeof(TimespanSecondsEncoder))] + internal TimeSpan Lifetime { get; set; } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/IMessageWithClientState.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/IMessageWithClientState.cs new file mode 100644 index 0000000..8054d27 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/IMessageWithClientState.cs @@ -0,0 +1,13 @@ +//----------------------------------------------------------------------- +// <copyright file="IMessageWithClientState.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using DotNetOpenAuth.Messaging; + + internal interface IMessageWithClientState : IProtocolMessage { + string ClientState { get; set; } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/MessageBase.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/MessageBase.cs new file mode 100644 index 0000000..9986d19 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/MessageBase.cs @@ -0,0 +1,205 @@ +//----------------------------------------------------------------------- +// <copyright file="MessageBase.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A common message base class for OAuth WRAP messages. + /// </summary> + public class MessageBase : IDirectedProtocolMessage, IDirectResponseProtocolMessage { + /// <summary> + /// A dictionary to contain extra message data. + /// </summary> + private Dictionary<string, string> extraData = new Dictionary<string, string>(); + + /// <summary> + /// The originating request. + /// </summary> + private IDirectedProtocolMessage originatingRequest; + + /// <summary> + /// The backing field for the <see cref="IMessage.Version"/> property. + /// </summary> + private Version version; + + /// <summary> + /// A value indicating whether this message is a direct or indirect message. + /// </summary> + private MessageTransport messageTransport; + + /// <summary> + /// Initializes a new instance of the <see cref="MessageBase"/> class + /// that is used for direct response messages. + /// </summary> + /// <param name="version">The version.</param> + protected MessageBase(Version version) { + Contract.Requires<ArgumentNullException>(version != null); + this.messageTransport = MessageTransport.Direct; + this.version = version; + } + + /// <summary> + /// Initializes a new instance of the <see cref="MessageBase"/> class. + /// </summary> + /// <param name="request">The originating request.</param> + protected MessageBase(IDirectedProtocolMessage request) { + Contract.Requires<ArgumentNullException>(request != null); + this.originatingRequest = request; + this.messageTransport = MessageTransport.Direct; + this.version = request.Version; + } + + /// <summary> + /// Initializes a new instance of the <see cref="MessageBase"/> class + /// that is used for directed messages. + /// </summary> + /// <param name="version">The version.</param> + /// <param name="messageTransport">The message transport.</param> + /// <param name="recipient">The recipient.</param> + protected MessageBase(Version version, MessageTransport messageTransport, Uri recipient) { + Contract.Requires<ArgumentNullException>(version != null); + Contract.Requires<ArgumentNullException>(recipient != null); + + this.version = version; + this.messageTransport = messageTransport; + this.Recipient = recipient; + this.HttpMethods = HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.PostRequest; + } + + #region IMessage Properties + + /// <summary> + /// Gets the version of the protocol or extension this message is prepared to implement. + /// </summary> + /// <remarks> + /// Implementations of this interface should ensure that this property never returns null. + /// </remarks> + Version IMessage.Version { + get { return this.version; } + } + + /// <summary> + /// Gets the extra, non-standard Protocol parameters included in the message. + /// </summary> + /// <value></value> + /// <remarks> + /// Implementations of this interface should ensure that this property never returns null. + /// </remarks> + public IDictionary<string, string> ExtraData { + get { return this.extraData; } + } + + #endregion + + #region IProtocolMessage Members + + /// <summary> + /// Gets the level of protection this message requires. + /// </summary> + /// <value><see cref="MessageProtections.None"/></value> + MessageProtections IProtocolMessage.RequiredProtection { + get { return MessageProtections.None; } + } + + /// <summary> + /// Gets a value indicating whether this is a direct or indirect message. + /// </summary> + /// <value></value> + MessageTransport IProtocolMessage.Transport { + get { return this.messageTransport; } + } + + #endregion + + #region IDirectedProtocolMessage Members + + /// <summary> + /// Gets the preferred method of transport for the message. + /// </summary> + /// <remarks> + /// For indirect messages this will likely be GET+POST, which both can be simulated in the user agent: + /// the GET with a simple 301 Redirect, and the POST with an HTML form in the response with javascript + /// to automate submission. + /// </remarks> + HttpDeliveryMethods IDirectedProtocolMessage.HttpMethods { + get { return this.HttpMethods; } + } + + /// <summary> + /// Gets the URL of the intended receiver of this message. + /// </summary> + Uri IDirectedProtocolMessage.Recipient { + get { return this.Recipient; } + } + + #endregion + + #region IDirectResponseProtocolMessage Members + + /// <summary> + /// Gets the originating request message that caused this response to be formed. + /// </summary> + IDirectedProtocolMessage IDirectResponseProtocolMessage.OriginatingRequest { + get { return this.originatingRequest; } + } + + #endregion + + /// <summary> + /// Gets or sets the preferred method of transport for the message. + /// </summary> + /// <remarks> + /// For indirect messages this will likely be GET+POST, which both can be simulated in the user agent: + /// the GET with a simple 301 Redirect, and the POST with an HTML form in the response with javascript + /// to automate submission. + /// </remarks> + protected HttpDeliveryMethods HttpMethods { get; set; } + + /// <summary> + /// Gets the URL of the intended receiver of this message. + /// </summary> + protected Uri Recipient { get; private set; } + + #region IMessage Methods + + /// <summary> + /// Checks the message state for conformity to the protocol specification + /// and throws an exception if the message is invalid. + /// </summary> + /// <remarks> + /// <para>Some messages have required fields, or combinations of fields that must relate to each other + /// in specialized ways. After deserializing a message, this method checks the state of the + /// message to see if it conforms to the protocol.</para> + /// <para>Note that this property should <i>not</i> check signatures or perform any state checks + /// outside this scope of this particular message.</para> + /// </remarks> + /// <exception cref="ProtocolException">Thrown if the message is invalid.</exception> + void IMessage.EnsureValidMessage() { + this.EnsureValidMessage(); + } + + #endregion + + /// <summary> + /// Checks the message state for conformity to the protocol specification + /// and throws an exception if the message is invalid. + /// </summary> + /// <remarks> + /// <para>Some messages have required fields, or combinations of fields that must relate to each other + /// in specialized ways. After deserializing a message, this method checks the state of the + /// message to see if it conforms to the protocol.</para> + /// <para>Note that this property should <i>not</i> check signatures or perform any state checks + /// outside this scope of this particular message.</para> + /// </remarks> + /// <exception cref="ProtocolException">Thrown if the message is invalid.</exception> + protected virtual void EnsureValidMessage() { + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/RefreshAccessTokenFailedResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/RefreshAccessTokenFailedResponse.cs new file mode 100644 index 0000000..43629c5 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/RefreshAccessTokenFailedResponse.cs @@ -0,0 +1,25 @@ +//----------------------------------------------------------------------- +// <copyright file="UserNamePasswordRefreshAccessTokenFailedResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + /// <summary> + /// A response from the Authorization Server to the Client to indicate that a + /// request for an access token renewal failed, probably due to an invalid + /// refresh token. + /// </summary> + /// <remarks> + /// This message type is shared by the Web App, Rich App, and Username/Password profiles. + /// </remarks> + internal class RefreshAccessTokenFailedResponse : UnauthorizedResponse { + /// <summary> + /// Initializes a new instance of the <see cref="RefreshAccessTokenFailedResponse"/> class. + /// </summary> + /// <param name="request">The request.</param> + internal RefreshAccessTokenFailedResponse(RefreshAccessTokenRequest request) + : base(request) { + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/RefreshAccessTokenRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/RefreshAccessTokenRequest.cs new file mode 100644 index 0000000..d72a958 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/RefreshAccessTokenRequest.cs @@ -0,0 +1,57 @@ +//----------------------------------------------------------------------- +// <copyright file="UserNamePasswordRefreshAccessTokenRequest.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A request from the client to the authorization server for a new access token + /// using a refresh token, after a previously supplied access token has expired. + /// </summary> + /// <remarks> + /// This message type is shared by the Web App, Rich App, and Username/Password profiles. + /// </remarks> + internal class RefreshAccessTokenRequest : MessageBase { + /// <summary> + /// Initializes a new instance of the <see cref="RefreshAccessTokenRequest"/> class. + /// </summary> + /// <param name="refreshTokenEndpoint">The authorization server's Refresh Token endpoint.</param> + /// <param name="version">The version.</param> + internal RefreshAccessTokenRequest(Uri refreshTokenEndpoint, Version version) + : base(version, MessageTransport.Direct, refreshTokenEndpoint) { + this.HttpMethods = HttpDeliveryMethods.PostRequest; + } + + /// <summary> + /// Gets or sets the refresh token that was received in + /// <see cref="UserNamePasswordSuccessResponse.RefreshToken"/>. + /// </summary> + /// <value>The refresh token.</value> + [MessagePart(Protocol.wrap_refresh_token, IsRequired = true, AllowEmpty = false)] + internal string RefreshToken { get; set; } + + /// <summary> + /// Checks the message state for conformity to the protocol specification + /// and throws an exception if the message is invalid. + /// </summary> + /// <remarks> + /// <para>Some messages have required fields, or combinations of fields that must relate to each other + /// in specialized ways. After deserializing a message, this method checks the state of the + /// message to see if it conforms to the protocol.</para> + /// <para>Note that this property should <i>not</i> check signatures or perform any state checks + /// outside this scope of this particular message.</para> + /// </remarks> + /// <exception cref="ProtocolException">Thrown if the message is invalid.</exception> + protected override void EnsureValidMessage() { + base.EnsureValidMessage(); + ErrorUtilities.VerifyProtocol(this.Recipient.IsTransportSecure(), OAuthWrapStrings.HttpsRequired); + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/RefreshAccessTokenSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/RefreshAccessTokenSuccessResponse.cs new file mode 100644 index 0000000..8a2b14a --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/RefreshAccessTokenSuccessResponse.cs @@ -0,0 +1,44 @@ +//----------------------------------------------------------------------- +// <copyright file="UserNamePasswordRefreshAccessTokenSuccessResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A response from the Authorization Server to the Consumer containing a delegation code + /// that the Consumer should use to obtain an access token. + /// </summary> + /// <remarks> + /// This message type is shared by the Web App, Rich App, and Username/Password profiles. + /// </remarks> + internal class RefreshAccessTokenSuccessResponse : MessageBase { + /// <summary> + /// Initializes a new instance of the <see cref="RefreshAccessTokenSuccessResponse"/> class. + /// </summary> + /// <param name="request">The request.</param> + internal RefreshAccessTokenSuccessResponse(RefreshAccessTokenRequest request) + : base(request) { + } + + /// <summary> + /// Gets or sets the access token. + /// </summary> + /// <value>The access token.</value> + [MessagePart(Protocol.wrap_access_token, IsRequired = true, AllowEmpty = false)] + internal string AccessToken { get; set; } + + /// <summary> + /// Gets or sets the lifetime of the access token. + /// </summary> + /// <value>The lifetime.</value> + [MessagePart(Protocol.wrap_access_token_expires_in, IsRequired = false, Encoder = typeof(TimespanSecondsEncoder))] + internal TimeSpan Lifetime { get; set; } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppAccessTokenFailedResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppAccessTokenFailedResponse.cs new file mode 100644 index 0000000..be4f001 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppAccessTokenFailedResponse.cs @@ -0,0 +1,21 @@ +//----------------------------------------------------------------------- +// <copyright file="RichAppAccessTokenFailedResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + /// <summary> + /// A response from the Authorization Server to the Client in the event + /// that an access token could not be granted. + /// </summary> + internal class RichAppAccessTokenFailedResponse : UnauthorizedResponse { + /// <summary> + /// Initializes a new instance of the <see cref="RichAppAccessTokenFailedResponse"/> class. + /// </summary> + /// <param name="request">The request.</param> + internal RichAppAccessTokenFailedResponse(RichAppAccessTokenRequest request) + : base(request) { + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppAccessTokenRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppAccessTokenRequest.cs new file mode 100644 index 0000000..f0ad943 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppAccessTokenRequest.cs @@ -0,0 +1,61 @@ +//----------------------------------------------------------------------- +// <copyright file="RichAppAccessTokenRequest.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A message from the Client to the Authorization Server exchanging a + /// verification code for refresh and access tokens. + /// </summary> + internal class RichAppAccessTokenRequest : MessageBase { + /// <summary> + /// Initializes a new instance of the <see cref="RichAppAccessTokenRequest"/> class. + /// </summary> + /// <param name="authorizationServer">The authorization server.</param> + /// <param name="version">The version.</param> + internal RichAppAccessTokenRequest(Uri authorizationServer, Version version) + : base(version, MessageTransport.Direct, authorizationServer) { + this.HttpMethods = HttpDeliveryMethods.PostRequest; + } + + /// <summary> + /// Gets or sets the identifier by which this client is known to the Authorization Server. + /// </summary> + /// <value>The client identifier.</value> + [MessagePart(Protocol.wrap_client_id, IsRequired = true, AllowEmpty = false)] + internal string ClientIdentifier { get; set; } + + /// <summary> + /// Gets or sets the verification code previously communicated to the Client + /// in <see cref="RichAppResponse.VerificationCode"/>. + /// </summary> + /// <value>The verification code.</value> + [MessagePart(Protocol.wrap_verification_code, IsRequired = true, AllowEmpty = false)] + internal string VerificationCode { get; set; } + + /// <summary> + /// Checks the message state for conformity to the protocol specification + /// and throws an exception if the message is invalid. + /// </summary> + /// <remarks> + /// <para>Some messages have required fields, or combinations of fields that must relate to each other + /// in specialized ways. After deserializing a message, this method checks the state of the + /// message to see if it conforms to the protocol.</para> + /// <para>Note that this property should <i>not</i> check signatures or perform any state checks + /// outside this scope of this particular message.</para> + /// </remarks> + /// <exception cref="ProtocolException">Thrown if the message is invalid.</exception> + protected override void EnsureValidMessage() { + base.EnsureValidMessage(); + ErrorUtilities.VerifyProtocol(this.Recipient.IsTransportSecure(), OAuthWrapStrings.HttpsRequired); + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppAccessTokenSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppAccessTokenSuccessResponse.cs new file mode 100644 index 0000000..8330176 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppAccessTokenSuccessResponse.cs @@ -0,0 +1,45 @@ +//----------------------------------------------------------------------- +// <copyright file="RichAppAccessTokenSuccessResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// The direct response message that contains the access token from the Authorization Server + /// to the Client. + /// </summary> + internal class RichAppAccessTokenSuccessResponse : MessageBase { + /// <summary> + /// Initializes a new instance of the <see cref="RichAppAccessTokenSuccessResponse"/> class. + /// </summary> + /// <param name="request">The request.</param> + internal RichAppAccessTokenSuccessResponse(RichAppAccessTokenRequest request) + : base(request) { + } + + /// <summary> + /// Gets or sets the refresh token. + /// </summary> + /// <value>The token.</value> + [MessagePart(Protocol.wrap_refresh_token, IsRequired = true, AllowEmpty = false)] + internal string RefreshToken { get; set; } + + /// <summary> + /// Gets or sets the access token. + /// </summary> + /// <value>The token.</value> + [MessagePart(Protocol.wrap_access_token, IsRequired = true, AllowEmpty = false)] + internal string AccessToken { get; set; } + + /// <summary> + /// Gets or sets the lifetime of the access token. + /// </summary> + /// <value>The lifetime.</value> + [MessagePart(Protocol.wrap_access_token_expires_in, IsRequired = false, AllowEmpty = false, Encoder = typeof(TimespanSecondsEncoder))] + internal TimeSpan? Lifetime { get; set; } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppRequest.cs new file mode 100644 index 0000000..9856687 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppRequest.cs @@ -0,0 +1,68 @@ +//----------------------------------------------------------------------- +// <copyright file="RichAppRequest.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A request from a rich app Client to an Authorization Server requested + /// authorization to access user Protected Data. + /// </summary> + internal class RichAppRequest : MessageBase { + /// <summary> + /// Initializes a new instance of the <see cref="RichAppRequest"/> class. + /// </summary> + /// <param name="authorizationServer">The authorization server.</param> + /// <param name="version">The version.</param> + internal RichAppRequest(Uri authorizationServer, Version version) + : base(version, MessageTransport.Indirect, authorizationServer) { + } + + /// <summary> + /// Gets or sets the client identifier previously obtained from the Authorization Server. + /// </summary> + /// <value>The client identifier.</value> + [MessagePart(Protocol.wrap_client_id, IsRequired = true, AllowEmpty = false)] + internal string ClientIdentifier { get; set; } + + /// <summary> + /// Gets or sets the callback URL. + /// </summary> + /// <value> + /// An absolute URL to which the Authorization Server will redirect the User back after + /// the user has approved the authorization request. + /// </value> + /// <remarks> + /// Authorization Servers MAY require that the wrap_callback URL match the previously + /// registered value for the Client Identifier. + /// </remarks> + [MessagePart(Protocol.wrap_callback, IsRequired = false, AllowEmpty = false)] + internal Uri Callback { get; set; } + + /// <summary> + /// Gets or sets state of the client that should be sent back with the authorization response. + /// </summary> + /// <value> + /// An opaque value that Clients can use to maintain state associated with this request. + /// </value> + /// <remarks> + /// If this value is present, the Authorization Server MUST return it to the Client's Callback URL. + /// </remarks> + [MessagePart(Protocol.wrap_client_state, IsRequired = false, AllowEmpty = true)] + internal string ClientState { get; set; } + + /// <summary> + /// Gets or sets the scope. + /// </summary> + /// <value>The Authorization Server MAY define authorization scope values for the Client to include.</value> + [MessagePart(Protocol.wrap_scope, IsRequired = false, AllowEmpty = true)] + internal string Scope { get; set; } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppResponse.cs new file mode 100644 index 0000000..678d956 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/RichApp/RichAppResponse.cs @@ -0,0 +1,60 @@ +//----------------------------------------------------------------------- +// <copyright file="RichAppResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// An indirect response from the Authorization Server to the rich app Client + /// with the verification code. + /// </summary> + internal class RichAppResponse : MessageBase { + /// <summary> + /// Initializes a new instance of the <see cref="RichAppResponse"/> class. + /// </summary> + /// <param name="clientCallback">The client callback.</param> + /// <param name="version">The version.</param> + internal RichAppResponse(Uri clientCallback, Version version) + : base(version, MessageTransport.Indirect, clientCallback) { + } + + /// <summary> + /// Gets or sets the verification code. + /// </summary> + /// <value> + /// The long-lived credential assigned by the Authorization Server to this Client for + /// use in accessing the authorizing user's protected resources. + /// </value> + [MessagePart(Protocol.wrap_verification_code, IsRequired = true, AllowEmpty = false)] + internal string VerificationCode { get; set; } + + /// <summary> + /// Gets or sets state of the client that should be sent back with the authorization response. + /// </summary> + /// <value> + /// An opaque value that Clients can use to maintain state associated with this request. + /// </value> + /// <remarks> + /// This parameter is required if the Client included it in <see cref="RichAppRequest.ClientState"/>. + /// </remarks> + [MessagePart(Protocol.wrap_client_state, IsRequired = false, AllowEmpty = true)] + internal string ClientState { get; set; } + + /// <summary> + /// Gets a value indicating whether the user granted the authorization request. + /// </summary> + /// <value> + /// <c>true</c> if authorization is granted; otherwise, <c>false</c>. + /// </value> + internal bool IsGranted { + get { return !string.IsNullOrEmpty(this.VerificationCode) && this.VerificationCode != Protocol.user_denied; } + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/UnauthorizedResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UnauthorizedResponse.cs new file mode 100644 index 0000000..901b6ff --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UnauthorizedResponse.cs @@ -0,0 +1,47 @@ +//----------------------------------------------------------------------- +// <copyright file="UnauthorizedResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System.Net; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A direct response that is simply a 401 Unauthorized with an + /// WWW-Authenticate: OAuth header. + /// </summary> + internal class UnauthorizedResponse : MessageBase, IHttpDirectResponse { + /// <summary> + /// Initializes a new instance of the <see cref="UnauthorizedResponse"/> class. + /// </summary> + /// <param name="request">The request.</param> + internal UnauthorizedResponse(IDirectedProtocolMessage request) + : base(request) { + } + + #region IHttpDirectResponse Members + + /// <summary> + /// Gets the HTTP status code that the direct response should be sent with. + /// </summary> + HttpStatusCode IHttpDirectResponse.HttpStatusCode { + get { return HttpStatusCode.Unauthorized; } + } + + /// <summary> + /// Gets the HTTP headers to add to the response. + /// </summary> + /// <value>May be an empty collection, but must not be <c>null</c>.</value> + WebHeaderCollection IHttpDirectResponse.Headers { + get { + return new WebHeaderCollection() { + { HttpResponseHeader.WwwAuthenticate, Protocol.HttpAuthorizationScheme }, + }; + } + } + + #endregion + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordCaptchaResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordCaptchaResponse.cs new file mode 100644 index 0000000..192af58 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordCaptchaResponse.cs @@ -0,0 +1,54 @@ +//----------------------------------------------------------------------- +// <copyright file="UsernamePasswordCaptchaResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A response from the Authorization Server indicating the Client must have the user + /// complete a CAPTCHA puzzle prior to authorization. + /// </summary> + internal class UsernamePasswordCaptchaResponse : MessageBase, IHttpDirectResponse { + /// <summary> + /// Initializes a new instance of the <see cref="UsernamePasswordCaptchaResponse"/> class. + /// </summary> + /// <param name="request">The request.</param> + internal UsernamePasswordCaptchaResponse(UserNamePasswordRequest request) + : base(request) { + } + + #region IHttpDirectResponse Members + + /// <summary> + /// Gets the HTTP status code that the direct response should be sent with. + /// </summary> + HttpStatusCode IHttpDirectResponse.HttpStatusCode { + get { return HttpStatusCode.BadRequest; } + } + + /// <summary> + /// Gets the HTTP headers to add to the response. + /// </summary> + /// <value>May be an empty collection, but must not be <c>null</c>.</value> + WebHeaderCollection IHttpDirectResponse.Headers { + get { return new WebHeaderCollection(); } + } + + #endregion + + /// <summary> + /// Gets or sets the URL to the CAPTCHA puzzle. + /// </summary> + /// <value>The captcha URL.</value> + [MessagePart(Protocol.wrap_captcha_url, IsRequired = true, AllowEmpty = false)] + internal Uri CaptchaPuzzle { get; set; } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordFailedResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordFailedResponse.cs new file mode 100644 index 0000000..fa98b83 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordFailedResponse.cs @@ -0,0 +1,22 @@ +//----------------------------------------------------------------------- +// <copyright file="UserNamePasswordFailedResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + /// <summary> + /// A response from the Authorization Server to the Consumer to indicate that a + /// request for a delegation code failed, probably due to an invalid + /// username and password. + /// </summary> + internal class UserNamePasswordFailedResponse : UnauthorizedResponse { + /// <summary> + /// Initializes a new instance of the <see cref="UserNamePasswordFailedResponse"/> class. + /// </summary> + /// <param name="request">The request.</param> + internal UserNamePasswordFailedResponse(UserNamePasswordRequest request) + : base(request) { + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordRequest.cs new file mode 100644 index 0000000..b4a72ff --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordRequest.cs @@ -0,0 +1,93 @@ +//----------------------------------------------------------------------- +// <copyright file="UserNamePasswordRequest.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A request for a delegation code in exchnage for a user's confidential + /// username and password. + /// </summary> + /// <remarks> + /// After this request has been sent, the consumer application MUST discard + /// the confidential user credentials and use the delegation code going forward. + /// </remarks> + internal class UserNamePasswordRequest : MessageBase { + /// <summary> + /// Initializes a new instance of the <see cref="UserNamePasswordRequest"/> class. + /// </summary> + /// <param name="authorizationServer">The authorization server.</param> + /// <param name="version">The version.</param> + internal UserNamePasswordRequest(Uri authorizationServer, Version version) + : base(version, MessageTransport.Direct, authorizationServer) { + this.HttpMethods = HttpDeliveryMethods.PostRequest; + } + + /// <summary> + /// Gets or sets the client identifier previously obtained from the Authorization Server. + /// </summary> + /// <value>The client identifier.</value> + [MessagePart(Protocol.wrap_client_id, IsRequired = true, AllowEmpty = false)] + internal string ClientIdentifier { get; set; } + + /// <summary> + /// Gets or sets the user's account username. + /// </summary> + /// <value>The username on the user's account.</value> + [MessagePart(Protocol.wrap_username, IsRequired = true, AllowEmpty = false)] + internal string UserName { get; set; } + + /// <summary> + /// Gets or sets the user's password. + /// </summary> + /// <value>The password.</value> + [MessagePart(Protocol.wrap_password, IsRequired = true, AllowEmpty = false)] + internal string Password { get; set; } + + /// <summary> + /// Gets or sets the CAPTCHA puzzle that the user just solved, if applicable. + /// </summary> + /// <value>The captcha puzzle location.</value> + [MessagePart(Protocol.wrap_captcha_url, IsRequired = false, AllowEmpty = false)] + internal Uri CaptchaPuzzle { get; set; } + + /// <summary> + /// Gets or sets the solution to the CAPTCHA puzzle the user just solved, if applicable. + /// </summary> + /// <value>The CAPTCHA solution.</value> + [MessagePart(Protocol.wrap_captcha_solution, IsRequired = false, AllowEmpty = false)] + internal string CaptchaSolution { get; set; } + + /// <summary> + /// Gets or sets the scope. + /// </summary> + /// <value>The scope.</value> + [MessagePart(Protocol.wrap_scope, IsRequired = false, AllowEmpty = true)] + internal string Scope { get; set; } + + /// <summary> + /// Checks the message state for conformity to the protocol specification + /// and throws an exception if the message is invalid. + /// </summary> + /// <remarks> + /// <para>Some messages have required fields, or combinations of fields that must relate to each other + /// in specialized ways. After deserializing a message, this method checks the state of the + /// message to see if it conforms to the protocol.</para> + /// <para>Note that this property should <i>not</i> check signatures or perform any state checks + /// outside this scope of this particular message.</para> + /// </remarks> + /// <exception cref="ProtocolException">Thrown if the message is invalid.</exception> + protected override void EnsureValidMessage() { + base.EnsureValidMessage(); + ErrorUtilities.VerifyProtocol(this.Recipient.IsTransportSecure(), OAuthWrapStrings.HttpsRequired); + ErrorUtilities.VerifyProtocol((this.CaptchaPuzzle == null) == (this.CaptchaSolution == null), "CAPTCHA puzzle and solution must either be both absent or both present."); + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordSuccessResponse.cs new file mode 100644 index 0000000..addae9f --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordSuccessResponse.cs @@ -0,0 +1,51 @@ +//----------------------------------------------------------------------- +// <copyright file="UserNamePasswordSuccessResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A response from the Authorization Server to the Client containing a refresh token + /// and an access token. + /// </summary> + internal class UserNamePasswordSuccessResponse : MessageBase { + /// <summary> + /// Initializes a new instance of the <see cref="UserNamePasswordSuccessResponse"/> class. + /// </summary> + /// <param name="request">The request.</param> + internal UserNamePasswordSuccessResponse(UserNamePasswordRequest request) + : base(request) { + } + + /// <summary> + /// Gets or sets the verification code. + /// </summary> + /// <value> + /// The long-lived credential assigned by the Authorization Server to this Client for + /// use in accessing the authorizing user's protected resources. + /// </value> + [MessagePart(Protocol.wrap_refresh_token, IsRequired = true, AllowEmpty = false)] + internal string RefreshToken { get; set; } + + /// <summary> + /// Gets or sets the access token. + /// </summary> + /// <value>The access token.</value> + [MessagePart(Protocol.wrap_access_token, IsRequired = true, AllowEmpty = false)] + internal string AccessToken { get; set; } + + /// <summary> + /// Gets or sets the lifetime of the access token. + /// </summary> + /// <value>The lifetime.</value> + [MessagePart(Protocol.wrap_access_token_expires_in, IsRequired = false, Encoder = typeof(TimespanSecondsEncoder))] + internal TimeSpan Lifetime { get; set; } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordVerificationResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordVerificationResponse.cs new file mode 100644 index 0000000..9b4602c --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/UsernameAndPassword/UserNamePasswordVerificationResponse.cs @@ -0,0 +1,55 @@ +//----------------------------------------------------------------------- +// <copyright file="UserNamePasswordVerificationResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A response from the Authorization Server to the client indicating that the user + /// must visit a URL to complete an additional verification step before proceeding. + /// </summary> + internal class UserNamePasswordVerificationResponse : MessageBase, IHttpDirectResponse { + /// <summary> + /// Initializes a new instance of the <see cref="UserNamePasswordVerificationResponse"/> class. + /// </summary> + /// <param name="request">The request.</param> + internal UserNamePasswordVerificationResponse(UserNamePasswordRequest request) + : base(request) { + } + + #region IHttpDirectResponse Members + + /// <summary> + /// Gets the HTTP status code that the direct response should be sent with. + /// </summary> + /// <value><see cref="HttpStatusCode.BadRequest"/></value> + HttpStatusCode IHttpDirectResponse.HttpStatusCode { + get { return HttpStatusCode.BadRequest; } + } + + /// <summary> + /// Gets the HTTP headers to add to the response. + /// </summary> + WebHeaderCollection IHttpDirectResponse.Headers { + get { return new WebHeaderCollection(); } + } + + #endregion + + /// <summary> + /// Gets or sets the verification URL the user must visit with a browser + /// to complete some step to defeat automated attacks. + /// </summary> + /// <value>The verification URL.</value> + [MessagePart(Protocol.wrap_verification_url, IsRequired = true, AllowEmpty = false)] + internal Uri VerificationUrl { get; set; } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenBadClientResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenBadClientResponse.cs new file mode 100644 index 0000000..6758e93 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenBadClientResponse.cs @@ -0,0 +1,22 @@ +//----------------------------------------------------------------------- +// <copyright file="WebAppAccessTokenBadClientResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + /// <summary> + /// A response from the Authorization Server to the Client in the event + /// that the <see cref="WebAppAccessTokenRequest"/> message had an + /// invalid Client Identifier and Client Secret combination. + /// </summary> + internal class WebAppAccessTokenBadClientResponse : UnauthorizedResponse { + /// <summary> + /// Initializes a new instance of the <see cref="WebAppAccessTokenBadClientResponse"/> class. + /// </summary> + /// <param name="request">The request.</param> + internal WebAppAccessTokenBadClientResponse(WebAppAccessTokenRequest request) + : base(request) { + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenFailedResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenFailedResponse.cs new file mode 100644 index 0000000..7cdc2a9 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenFailedResponse.cs @@ -0,0 +1,56 @@ +//----------------------------------------------------------------------- +// <copyright file="WebAppAccessTokenFailedResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net; + using System.Text; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// A response from the Authorization Server to the Client in the event + /// that the <see cref="WebAppAccessTokenRequest"/> message had an + /// invalid calback URL or verification code. + /// </summary> + internal class WebAppAccessTokenFailedResponse : MessageBase, IHttpDirectResponse { + /// <summary> + /// Initializes a new instance of the <see cref="WebAppAccessTokenFailedResponse"/> class. + /// </summary> + /// <param name="request">The request.</param> + internal WebAppAccessTokenFailedResponse(WebAppAccessTokenRequest request) + : base(request) { + } + + #region IHttpDirectResponse Members + + /// <summary> + /// Gets the HTTP status code that the direct response should be sent with. + /// </summary> + /// <value></value> + HttpStatusCode IHttpDirectResponse.HttpStatusCode { + get { return System.Net.HttpStatusCode.BadRequest; } + } + + /// <summary> + /// Gets the HTTP headers to add to the response. + /// </summary> + /// <value>May be an empty collection, but must not be <c>null</c>.</value> + WebHeaderCollection IHttpDirectResponse.Headers { + get { return new WebHeaderCollection(); } + } + + #endregion + + /// <summary> + /// Gets or sets the error reason. + /// </summary> + /// <value>"expired_verification_code" or "invalid_callback".</value> + [MessagePart(Protocol.wrap_error_reason, IsRequired = false, AllowEmpty = true)] + internal string ErrorReason { get; set; } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenRequest.cs new file mode 100644 index 0000000..904207e --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenRequest.cs @@ -0,0 +1,90 @@ +//----------------------------------------------------------------------- +// <copyright file="WebAppAccessTokenRequest.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuthWrap.ChannelElements; + using System.Diagnostics.Contracts; + + /// <summary> + /// A message sent by the Client directly to the Authorization Server to exchange + /// the verification code for an Access Token. + /// </summary> + /// <remarks> + /// Used by the Web App (and Rich App?) profiles. + /// </remarks> + internal class WebAppAccessTokenRequest : MessageBase { + /// <summary> + /// Initializes a new instance of the <see cref="WebAppAccessTokenRequest"/> class. + /// </summary> + /// <param name="accessTokenEndpoint">The Authorization Server's access token endpoint URL.</param> + /// <param name="version">The version.</param> + internal WebAppAccessTokenRequest(Uri accessTokenEndpoint, Version version) + : base(version, MessageTransport.Direct, accessTokenEndpoint) { + this.HttpMethods = HttpDeliveryMethods.PostRequest; + } + + /// <summary> + /// Initializes a new instance of the <see cref="WebAppAccessTokenRequest"/> class. + /// </summary> + /// <param name="authorizationServer">The authorization server.</param> + internal WebAppAccessTokenRequest(AuthorizationServerDescription authorizationServer) + : this(authorizationServer.AccessTokenEndpoint, authorizationServer.Version) { + Contract.Requires<ArgumentNullException>(authorizationServer != null); + Contract.Requires<ArgumentException>(authorizationServer.Version != null); + Contract.Requires<ArgumentException>(authorizationServer.AccessTokenEndpoint != null); + } + + /// <summary> + /// Gets or sets the identifier by which this client is known to the Authorization Server. + /// </summary> + /// <value>The client identifier.</value> + [MessagePart(Protocol.wrap_client_id, IsRequired = true, AllowEmpty = false)] + internal string ClientIdentifier { get; set; } + + /// <summary> + /// Gets or sets the client secret. + /// </summary> + /// <value>The client secret.</value> + [MessagePart(Protocol.wrap_client_secret, IsRequired = true, AllowEmpty = false)] + internal string ClientSecret { get; set; } + + /// <summary> + /// Gets or sets the verification code previously communicated to the Client + /// in <see cref="WebAppSuccessResponse.VerificationCode"/>. + /// </summary> + /// <value>The verification code.</value> + [MessagePart(Protocol.wrap_verification_code, IsRequired = true, AllowEmpty = false)] + internal string VerificationCode { get; set; } + + /// <summary> + /// Gets or sets the callback URL used in <see cref="WebAppRequest.Callback"/> + /// </summary> + /// <value> + /// The Callback URL used to obtain the Verification Code. + /// </value> + [MessagePart(Protocol.wrap_callback, IsRequired = true, AllowEmpty = false)] + internal Uri Callback { get; set; } + + /// <summary> + /// Checks the message state for conformity to the protocol specification + /// and throws an exception if the message is invalid. + /// </summary> + /// <remarks> + /// <para>Some messages have required fields, or combinations of fields that must relate to each other + /// in specialized ways. After deserializing a message, this method checks the state of the + /// message to see if it conforms to the protocol.</para> + /// <para>Note that this property should <i>not</i> check signatures or perform any state checks + /// outside this scope of this particular message.</para> + /// </remarks> + /// <exception cref="ProtocolException">Thrown if the message is invalid.</exception> + protected override void EnsureValidMessage() { + base.EnsureValidMessage(); + ErrorUtilities.VerifyProtocol(this.Recipient.IsTransportSecure(), OAuthWrapStrings.HttpsRequired); + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenSuccessResponse.cs new file mode 100644 index 0000000..ec44712 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppAccessTokenSuccessResponse.cs @@ -0,0 +1,45 @@ +//----------------------------------------------------------------------- +// <copyright file="WebAppAccessTokenSuccessResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// The direct response message that contains the access token from the Authorization Server + /// to the Client. + /// </summary> + internal class WebAppAccessTokenSuccessResponse : MessageBase { + /// <summary> + /// Initializes a new instance of the <see cref="WebAppAccessTokenSuccessResponse"/> class. + /// </summary> + /// <param name="request">The request.</param> + internal WebAppAccessTokenSuccessResponse(WebAppAccessTokenRequest request) + : base(request) { + } + + /// <summary> + /// Gets or sets the refresh token. + /// </summary> + /// <value>The token.</value> + [MessagePart(Protocol.wrap_refresh_token, IsRequired = true, AllowEmpty = false)] + internal string RefreshToken { get; set; } + + /// <summary> + /// Gets or sets the access token. + /// </summary> + /// <value>The token.</value> + [MessagePart(Protocol.wrap_access_token, IsRequired = true, AllowEmpty = false)] + internal string AccessToken { get; set; } + + /// <summary> + /// Gets or sets the lifetime of the access token. + /// </summary> + /// <value>The lifetime.</value> + [MessagePart(Protocol.wrap_access_token_expires_in, IsRequired = false, AllowEmpty = false, Encoder = typeof(TimespanSecondsEncoder))] + internal TimeSpan? Lifetime { get; set; } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppFailedResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppFailedResponse.cs new file mode 100644 index 0000000..fd7f546 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppFailedResponse.cs @@ -0,0 +1,47 @@ +//----------------------------------------------------------------------- +// <copyright file="WebAppFailedResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using System.Diagnostics.Contracts; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// The message the Authorization Server MAY use to send the user back to the Client + /// following the user's denial to grant Consumer with authorization of + /// access to requested resources. + /// </summary> + internal class WebAppFailedResponse : MessageBase, IMessageWithClientState { + /// <summary> + /// A constant parameter that indicates the user refused to grant the requested authorization. + /// </summary> + [MessagePart(Protocol.wrap_error_reason, IsRequired = true)] + private const string ErrorReason = Protocol.user_denied; + + /// <summary> + /// Initializes a new instance of the <see cref="WebAppFailedResponse"/> class. + /// </summary> + /// <param name="clientCallback">The recipient of the message.</param> + /// <param name="version">The version.</param> + internal WebAppFailedResponse(Uri clientCallback, Version version) : + base(version, MessageTransport.Indirect, clientCallback) { + Contract.Requires<ArgumentNullException>(version != null); + Contract.Requires<ArgumentNullException>(clientCallback != null); + } + + /// <summary> + /// Gets or sets the state of the client that was supplied to the Authorization Server. + /// </summary> + /// <value> + /// An opaque value that Clients can use to maintain state associated with the authorization request. + /// </value> + /// <remarks> + /// If this value is present, the Authorization Server MUST return it to the Client's callback URL. + /// </remarks> + [MessagePart(Protocol.wrap_client_state, IsRequired = false, AllowEmpty = true)] + internal string ClientState { get; set; } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppRequest.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppRequest.cs new file mode 100644 index 0000000..5166342 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppRequest.cs @@ -0,0 +1,80 @@ +//----------------------------------------------------------------------- +// <copyright file="WebAppRequest.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuthWrap.ChannelElements; + using System.Diagnostics.Contracts; + + /// <summary> + /// A message sent by a web application Client to the AuthorizationServer + /// via the user agent to obtain authorization from the user and prepare + /// to issue an access token to the Consumer if permission is granted. + /// </summary> + internal class WebAppRequest : MessageBase, IMessageWithClientState { + /// <summary> + /// Initializes a new instance of the <see cref="WebAppRequest"/> class. + /// </summary> + /// <param name="userAuthorizationEndpoint">The Authorization Server's user authorization URL to direct the user to.</param> + /// <param name="version">The protocol version.</param> + internal WebAppRequest(Uri userAuthorizationEndpoint, Version version) + : base(version, MessageTransport.Indirect, userAuthorizationEndpoint) { + Contract.Requires<ArgumentNullException>(userAuthorizationEndpoint != null); + Contract.Requires<ArgumentNullException>(version != null); + } + + /// <summary> + /// Initializes a new instance of the <see cref="WebAppRequest"/> class. + /// </summary> + /// <param name="authorizationServer">The authorization server.</param> + internal WebAppRequest(AuthorizationServerDescription authorizationServer) + : this(authorizationServer.UserAuthorizationEndpoint, authorizationServer.Version) { + Contract.Requires<ArgumentNullException>(authorizationServer != null); + Contract.Requires<ArgumentException>(authorizationServer.Version != null); + Contract.Requires<ArgumentException>(authorizationServer.UserAuthorizationEndpoint != null); + } + + /// <summary> + /// Gets or sets the identifier by which this client is known to the Authorization Server. + /// </summary> + [MessagePart(Protocol.wrap_client_id, IsRequired = true, AllowEmpty = false)] + internal string ClientIdentifier { get; set; } + + /// <summary> + /// Gets or sets the callback URL. + /// </summary> + /// <value> + /// An absolute URL to which the Authorization Server will redirect the User back after + /// the user has approved the authorization request. + /// </value> + /// <remarks> + /// Authorization Servers MAY require that the wrap_callback URL match the previously + /// registered value for the Client Identifier. + /// </remarks> + [MessagePart(Protocol.wrap_callback, IsRequired = true, AllowEmpty = false)] + internal Uri Callback { get; set; } + + /// <summary> + /// Gets or sets state of the client that should be sent back with the authorization response. + /// </summary> + /// <value> + /// An opaque value that Clients can use to maintain state associated with this request. + /// </value> + /// <remarks> + /// If this value is present, the Authorization Server MUST return it to the Client's Callback URL. + /// </remarks> + [MessagePart(Protocol.wrap_client_state, IsRequired = false, AllowEmpty = true)] + internal string ClientState { get; set; } + + /// <summary> + /// Gets or sets the scope. + /// </summary> + /// <value>The Authorization Server MAY define authorization scope values for the Client to include.</value> + [MessagePart(Protocol.wrap_scope, IsRequired = false, AllowEmpty = true)] + internal string Scope { get; set; } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppSuccessResponse.cs new file mode 100644 index 0000000..ec13da4 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Messages/WebApp/WebAppSuccessResponse.cs @@ -0,0 +1,49 @@ +//----------------------------------------------------------------------- +// <copyright file="WebAppSuccessResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap.Messages { + using System; + using System.Diagnostics.Contracts; + using DotNetOpenAuth.Messaging; + + /// <summary> + /// The message sent by the Authorization Server to the Client via the user agent + /// to indicate that user authorization was granted, and to return the user + /// to the Client where they started their experience. + /// </summary> + internal class WebAppSuccessResponse : MessageBase, IMessageWithClientState { + /// <summary> + /// Initializes a new instance of the <see cref="WebAppSuccessResponse"/> class. + /// </summary> + /// <param name="clientCallback">The client callback.</param> + /// <param name="version">The protocol version.</param> + internal WebAppSuccessResponse(Uri clientCallback, Version version) + : base(version, MessageTransport.Indirect, clientCallback) { + Contract.Requires<ArgumentNullException>(version != null); + Contract.Requires<ArgumentNullException>(clientCallback != null); + } + + /// <summary> + /// Gets or sets the verification code. + /// </summary> + /// <value> + /// The long-lived credential assigned by the Authorization Server to this Consumer for + /// use in accessing the authorizing user's protected resources. + /// </value> + [MessagePart(Protocol.wrap_verification_code, IsRequired = true, AllowEmpty = true)] + internal string VerificationCode { get; set; } + + /// <summary> + /// Gets or sets some state as provided by the client in the authorization request. + /// </summary> + /// <value>An opaque value defined by the client.</value> + /// <remarks> + /// REQUIRED if the Client sent the value in the <see cref="WebAppRequest"/>. + /// </remarks> + [MessagePart(Protocol.wrap_client_state, IsRequired = false, AllowEmpty = true)] + internal string ClientState { get; set; } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.Designer.cs b/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.Designer.cs new file mode 100644 index 0000000..27879c4 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.Designer.cs @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:4.0.30128.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace DotNetOpenAuth.OAuthWrap { + using System; + + + /// <summary> + /// A strongly-typed resource class, for looking up localized strings, etc. + /// </summary> + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class OAuthWrapStrings { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal OAuthWrapStrings() { + } + + /// <summary> + /// Returns the cached ResourceManager instance used by this class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DotNetOpenAuth.OAuthWrap.OAuthWrapStrings", typeof(OAuthWrapStrings).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// <summary> + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// <summary> + /// Looks up a localized string similar to This message can only be sent over HTTPS.. + /// </summary> + internal static string HttpsRequired { + get { + return ResourceManager.GetString("HttpsRequired", resourceCulture); + } + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.resx b/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.resx new file mode 100644 index 0000000..b8a8d62 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.resx @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <data name="HttpsRequired" xml:space="preserve"> + <value>This message can only be sent over HTTPS.</value> + </data> +</root>
\ No newline at end of file diff --git a/src/DotNetOpenAuth/OAuthWrap/Protocol.cs b/src/DotNetOpenAuth/OAuthWrap/Protocol.cs new file mode 100644 index 0000000..b8e3962 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/Protocol.cs @@ -0,0 +1,188 @@ +// <auto-generated/> // disable StyleCop on this file +//----------------------------------------------------------------------- +// <copyright file="Protocol.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap { + using System; + using System.Collections.Generic; + + /// <summary> + /// An enumeration of the OAuth WRAP protocol versions supported by this library. + /// </summary> + public enum ProtocolVersion { + /// <summary> + /// The OAuth WRAP 1.0 specification. + /// </summary> + V10, + } + + /// <summary> + /// Protocol constants for OAuth WRAP. + /// </summary> + internal class Protocol { + /// <summary> + /// The HTTP authorization scheme "WRAP"; + /// </summary> + internal const string HttpAuthorizationScheme = "WRAP"; + + /// <summary> + /// The format of the HTTP Authorization header value that authorizes OAuth WRAP requests. + /// </summary> + internal const string HttpAuthorizationHeaderFormat = "WRAP access_token=\"{0}\""; + + /// <summary> + /// The "wrap_client_state" string. + /// </summary> + internal const string wrap_client_state = "wrap_client_state"; + + /// <summary> + /// The "wrap_callback" string. + /// </summary> + internal const string wrap_callback = "wrap_callback"; + + /// <summary> + /// The "wrap_client_id" string. + /// </summary> + internal const string wrap_client_id = "wrap_client_id"; + + /// <summary> + /// The "wrap_scope" string. + /// </summary> + internal const string wrap_scope = "wrap_scope"; + + /// <summary> + /// The "wrap_client_secret" string. + /// </summary> + internal const string wrap_client_secret = "wrap_client_secret"; + + /// <summary> + /// The "wrap_verification_code" string. + /// </summary> + internal const string wrap_verification_code = "wrap_verification_code"; + + /// <summary> + /// The "wrap_verification_url" string. + /// </summary> + internal const string wrap_verification_url = "wrap_verification_url"; + + /// <summary> + /// The "wrap_error_reason" string. + /// </summary> + internal const string wrap_error_reason = "wrap_error_reason"; + + /// <summary> + /// The "wrap_access_token" string. + /// </summary> + internal const string wrap_access_token = "wrap_access_token"; + + /// <summary> + /// The "wrap_refresh_token" string. + /// </summary> + internal const string wrap_refresh_token = "wrap_refresh_token"; + + /// <summary> + /// The "wrap_access_token_expires_in" string. + /// </summary> + internal const string wrap_access_token_expires_in = "wrap_access_token_expires_in"; + + /// <summary> + /// The "expired_delegation_code" string. + /// </summary> + internal const string expired_delegation_code = "expired_delegation_code"; + + /// <summary> + /// The "wrap_username" string. + /// </summary> + internal const string wrap_username = "wrap_username"; + + /// <summary> + /// The "wrap_password" string. + /// </summary> + internal const string wrap_password = "wrap_password"; + + /// <summary> + /// The "wrap_name" string. + /// </summary> + internal const string wrap_name = "wrap_name"; + + /// <summary> + /// The "wrap_assertion_format" string. + /// </summary> + internal const string wrap_assertion_format = "wrap_assertion_format"; + + /// <summary> + /// The "wrap_assertion" string. + /// </summary> + internal const string wrap_assertion = "wrap_assertion"; + + /// <summary> + /// The "wrap_SAML" string. + /// </summary> + internal const string wrap_saml = "wrap_SAML"; + + /// <summary> + /// The "wrap_SWT" string. + /// </summary> + internal const string wrap_swt = "wrap_SWT"; + + /// <summary> + /// The "wrap_captcha_url" string. + /// </summary> + internal const string wrap_captcha_url = "wrap_captcha_url"; + + /// <summary> + /// The "wrap_captcha_solution" string. + /// </summary> + internal const string wrap_captcha_solution = "wrap_captcha_solution"; + + /// <summary> + /// The "user_denied" string. + /// </summary> + internal const string user_denied = "user_denied"; + + /// <summary> + /// Gets the <see cref="Protocol"/> instance with values initialized for V1.0 of the protocol. + /// </summary> + internal static readonly Protocol V10 = new Protocol { + Version = new Version(1, 0), + ProtocolVersion = ProtocolVersion.V10, + }; + + /// <summary> + /// A list of all supported OAuth versions, in order starting from newest version. + /// </summary> + internal static readonly List<Protocol> AllVersions = new List<Protocol>() { V10 }; + + /// <summary> + /// The default (or most recent) supported version of the OpenID protocol. + /// </summary> + internal static readonly Protocol Default = AllVersions[0]; + + /// <summary> + /// Gets or sets the OAuth WRAP version represented by this instance. + /// </summary> + /// <value>The version.</value> + internal Version Version { get; private set; } + + /// <summary> + /// Gets or sets the OAuth WRAP version represented by this instance. + /// </summary> + /// <value>The protocol version.</value> + internal ProtocolVersion ProtocolVersion { get; private set; } + + /// <summary> + /// Gets the OAuth Protocol instance to use for the given version. + /// </summary> + /// <param name="version">The OAuth version to get.</param> + /// <returns>A matching <see cref="Protocol"/> instance.</returns> + public static Protocol Lookup(ProtocolVersion version) { + switch (version) { + case ProtocolVersion.V10: return Protocol.V10; + default: throw new ArgumentOutOfRangeException("version"); + } + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/WebAppClient.cs b/src/DotNetOpenAuth/OAuthWrap/WebAppClient.cs new file mode 100644 index 0000000..f107180 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/WebAppClient.cs @@ -0,0 +1,107 @@ +//----------------------------------------------------------------------- +// <copyright file="WebAppClient.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap { + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + using System.Linq; + using System.Text; + using System.Web; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuthWrap.Messages; + + /// <summary> + /// An OAuth WRAP consumer designed for web applications. + /// </summary> + public class WebAppClient : ClientBase { + /// <summary> + /// Initializes a new instance of the <see cref="WebAppClient"/> class. + /// </summary> + /// <param name="authorizationServer">The authorization server.</param> + public WebAppClient(AuthorizationServerDescription authorizationServer) + : base(authorizationServer) { + } + + /// <summary> + /// Gets or sets the identifier by which this client is known to the Authorization Server. + /// </summary> + public string ClientIdentifier { get; set; } + + /// <summary> + /// Gets or sets the client secret shared with the Authorization Server. + /// </summary> + public string ClientSecret { get; set; } + + public IClientTokenManager TokenManager { get; set; } + + public WebAppRequest PrepareRequestUserAuthorization(IWrapAuthorization authorizationState) { + Contract.Requires<ArgumentNullException>(authorizationState != null); + Contract.Requires<InvalidOperationException>(authorizationState.Callback != null || (HttpContext.Current != null && HttpContext.Current.Request != null), MessagingStrings.HttpContextRequired); + Contract.Requires<InvalidOperationException>(!string.IsNullOrEmpty(this.ClientIdentifier)); + Contract.Ensures(Contract.Result<WebAppRequest>() != null); + Contract.Ensures(Contract.Result<WebAppRequest>().Callback == authorizationState.Callback); + Contract.Ensures(Contract.Result<WebAppRequest>().ClientIdentifier == this.ClientIdentifier); + + if (authorizationState.Callback == null) { + authorizationState.Callback = this.Channel.GetRequestFromContext().UrlBeforeRewriting; + } + + var request = new WebAppRequest(this.AuthorizationServer) { + ClientIdentifier = this.ClientIdentifier, + Callback = authorizationState.Callback, + Scope = authorizationState.Scope, + }; + + return request; + } + + public IWrapAuthorization ProcessUserAuthorization() { + Contract.Requires<InvalidOperationException>(HttpContext.Current != null && HttpContext.Current.Request != null, MessagingStrings.HttpContextRequired); + return this.ProcessUserAuthorization(this.Channel.GetRequestFromContext()); + } + + public IWrapAuthorization ProcessUserAuthorization(HttpRequestInfo request) { + Contract.Requires<ArgumentNullException>(request != null); + Contract.Requires<InvalidOperationException>(!string.IsNullOrEmpty(this.ClientIdentifier)); + Contract.Requires<InvalidOperationException>(!string.IsNullOrEmpty(this.ClientSecret)); + var response = this.Channel.ReadFromRequest<IMessageWithClientState>(request); + if (response != null) { + IWrapAuthorization authorizationState = this.TokenManager.GetAuthorizationState(request.UrlBeforeRewriting, response.ClientState); + ErrorUtilities.VerifyProtocol(authorizationState != null, "Unexpected OAuth WRAP authorization response received with callback and client state that does not match an expected value."); + var success = response as WebAppSuccessResponse; + var failure = response as WebAppFailedResponse; + ErrorUtilities.VerifyProtocol(success != null || failure != null, MessagingStrings.UnexpectedMessageReceivedOfMany); + if (success != null) { + var accessTokenRequest = new WebAppAccessTokenRequest(this.AuthorizationServer) { + ClientSecret = this.ClientSecret, + ClientIdentifier = this.ClientIdentifier, + Callback = authorizationState.Callback, + VerificationCode = success.VerificationCode, + }; + IProtocolMessage accessTokenResponse = this.Channel.Request(accessTokenRequest); + var accessTokenSuccess = accessTokenResponse as WebAppAccessTokenSuccessResponse; + var badClientAccessTokenResponse = accessTokenResponse as WebAppAccessTokenBadClientResponse; + var failedAccessTokenResponse = accessTokenResponse as WebAppAccessTokenFailedResponse; + if (accessTokenSuccess != null) { + authorizationState.AccessToken = accessTokenSuccess.AccessToken; + authorizationState.RefreshToken = accessTokenSuccess.RefreshToken; + authorizationState.AccessTokenExpirationUtc = DateTime.UtcNow + accessTokenSuccess.Lifetime; + } else if (badClientAccessTokenResponse != null) { + ErrorUtilities.ThrowProtocol("Failed to obtain access token due to invalid Client Identifier or Client Secret."); + } else { // failedAccessTokenResponse != null + ErrorUtilities.ThrowProtocol("Failed to obtain access token. Authorization Server reports reason: {0}", failedAccessTokenResponse.ErrorReason); + } + } else { // failure + } + + return authorizationState; + } + + return null; + } + } +} diff --git a/src/DotNetOpenAuth/OAuthWrap/WrapUtilities.cs b/src/DotNetOpenAuth/OAuthWrap/WrapUtilities.cs new file mode 100644 index 0000000..a892364 --- /dev/null +++ b/src/DotNetOpenAuth/OAuthWrap/WrapUtilities.cs @@ -0,0 +1,34 @@ +//----------------------------------------------------------------------- +// <copyright file="WrapUtilities.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuthWrap { + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + using System.Globalization; + using System.Linq; + using System.Net; + using System.Text; + + /// <summary> + /// Some common utility methods for OAuth WRAP. + /// </summary> + public static class WrapUtilities { + /// <summary> + /// Authorizes an HTTP request using an OAuth WRAP access token in an HTTP Authorization header. + /// </summary> + /// <param name="request">The request to authorize.</param> + /// <param name="accessToken">The access token previously obtained from the Authorization Server.</param> + public static void AuthorizeWithOAuthWrap(this HttpWebRequest request, string accessToken) { + Contract.Requires<ArgumentNullException>(request != null); + Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(accessToken)); + request.Headers[HttpRequestHeader.Authorization] = string.Format( + CultureInfo.InvariantCulture, + Protocol.HttpAuthorizationHeaderFormat, + accessToken); + } + } +} diff --git a/src/DotNetOpenAuth/OpenId/Messages/DirectErrorResponse.cs b/src/DotNetOpenAuth/OpenId/Messages/DirectErrorResponse.cs index ad20ff7..ec2f7d5 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/DirectErrorResponse.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/DirectErrorResponse.cs @@ -36,6 +36,14 @@ namespace DotNetOpenAuth.OpenId.Messages { get { return HttpStatusCode.BadRequest; } } + /// <summary> + /// Gets the HTTP headers to add to the response. + /// </summary> + /// <value>May be an empty collection, but must not be <c>null</c>.</value> + WebHeaderCollection IHttpDirectResponse.Headers { + get { return new WebHeaderCollection(); } + } + #endregion /// <summary> |