diff --git a/Release/include/cpprest/oauth2.h b/Release/include/cpprest/oauth2.h
index 202d1520e9..f146990e9b 100644
--- a/Release/include/cpprest/oauth2.h
+++ b/Release/include/cpprest/oauth2.h
@@ -18,7 +18,8 @@
*
* HTTP Library: Oauth 2.0
*
-* For the latest on this and related APIs, please see: https://github.com/Microsoft/cpprestsdk
+* For the latest on this and related APIs, please see:
+*https://github.com/Microsoft/cpprestsdk
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/
@@ -28,516 +29,677 @@
#define _CASA_OAUTH2_H
#include "cpprest/http_msg.h"
+#include "cpprest/details/web_utilities.h"
-namespace web
-{
-namespace http
-{
-namespace client
-{
- // Forward declaration to avoid circular include dependency.
- class http_client_config;
-}
+namespace web {
+namespace http {
+ namespace client {
+ // Forward declaration to avoid circular include dependency.
+ class http_client_config;
+ }
-/// oAuth 2.0 library.
-namespace oauth2
-{
-namespace details
-{
+ /// oAuth 2.0 library.
+ namespace oauth2 {
+ namespace details {
-class oauth2_handler;
+ class oauth2_handler;
-// Constant strings for OAuth 2.0.
-typedef utility::string_t oauth2_string;
-class oauth2_strings
-{
-public:
+ // Constant strings for OAuth 2.0.
+ typedef utility::string_t oauth2_string;
+ class oauth2_strings {
+ public:
#define _OAUTH2_STRINGS
#define DAT(a_, b_) _ASYNCRTIMP static const oauth2_string a_;
#include "cpprest/details/http_constants.dat"
#undef _OAUTH2_STRINGS
#undef DAT
-};
-
-} // namespace web::http::oauth2::details
-
-/// oAuth functionality is currently in beta.
-namespace experimental
-{
-
-///
-/// Exception type for OAuth 2.0 errors.
-///
-class oauth2_exception : public std::exception
-{
-public:
- oauth2_exception(utility::string_t msg) : m_msg(utility::conversions::to_utf8string(std::move(msg))) {}
- ~oauth2_exception() CPPREST_NOEXCEPT {}
- const char* what() const CPPREST_NOEXCEPT { return m_msg.c_str(); }
-
-private:
- std::string m_msg;
-};
-
-///
-/// OAuth 2.0 token and associated information.
-///
-class oauth2_token
-{
-public:
-
- ///
- /// Value for undefined expiration time in expires_in().
- ///
- enum { undefined_expiration = -1 };
-
- oauth2_token(utility::string_t access_token=utility::string_t()) :
- m_access_token(std::move(access_token)),
- m_expires_in(undefined_expiration)
- {}
-
- ///
- /// Get access token validity state.
- /// If true, access token is a valid.
- ///
- /// Access token validity state.
- bool is_valid_access_token() const { return !access_token().empty(); }
-
- ///
- /// Get access token.
- ///
- /// Access token string.
- const utility::string_t& access_token() const { return m_access_token; }
- ///
- /// Set access token.
- ///
- /// Access token string to set.
- void set_access_token(utility::string_t access_token) { m_access_token = std::move(access_token); }
-
- ///
- /// Get refresh token.
- ///
- /// Refresh token string.
- const utility::string_t& refresh_token() const { return m_refresh_token; }
- ///
- /// Set refresh token.
- ///
- /// Refresh token string to set.
- void set_refresh_token(utility::string_t refresh_token) { m_refresh_token = std::move(refresh_token); }
-
- ///
- /// Get token type.
- ///
- /// Token type string.
- const utility::string_t& token_type() const { return m_token_type; }
- ///
- /// Set token type.
- ///
- /// Token type string to set.
- void set_token_type(utility::string_t token_type) { m_token_type = std::move(token_type); }
-
- ///
- /// Get token scope.
- ///
- /// Token scope string.
- const utility::string_t& scope() const { return m_scope; }
- ///
- /// Set token scope.
- ///
- /// Token scope string to set.
- void set_scope(utility::string_t scope) { m_scope = std::move(scope); }
-
- ///
- /// Get the lifetime of the access token in seconds.
- /// For example, 3600 means the access token will expire in one hour from
- /// the time when access token response was generated by the authorization server.
- /// Value of undefined_expiration means expiration time is either
- /// unset or that it was not returned by the server with the access token.
- ///
- /// Lifetime of the access token in seconds or undefined_expiration if not set.
- int64_t expires_in() const { return m_expires_in; }
- ///
- /// Set lifetime of access token (in seconds).
- ///
- /// Lifetime of access token in seconds.
- void set_expires_in(int64_t expires_in) { m_expires_in = expires_in; }
-
-private:
- utility::string_t m_access_token;
- utility::string_t m_refresh_token;
- utility::string_t m_token_type;
- utility::string_t m_scope;
- int64_t m_expires_in;
-};
-
-///
-/// OAuth 2.0 configuration.
-///
-/// Encapsulates functionality for:
-/// - Authenticating requests with an access token.
-/// - Performing the OAuth 2.0 authorization code grant authorization flow.
-/// See: http://tools.ietf.org/html/rfc6749#section-4.1
-/// - Performing the OAuth 2.0 implicit grant authorization flow.
-/// See: http://tools.ietf.org/html/rfc6749#section-4.2
-///
-/// Performing OAuth 2.0 authorization:
-/// 1. Set service and client/app parameters:
-/// - Client/app key & secret (as provided by the service).
-/// - The service authorization endpoint and token endpoint.
-/// - Your client/app redirect URI.
-/// - Use set_state() to assign a unique state string for the authorization
-/// session (default: "").
-/// - If needed, use set_bearer_auth() to control bearer token passing in either
-/// query or header (default: header). See: http://tools.ietf.org/html/rfc6750#section-2
-/// - If needed, use set_access_token_key() to set "non-standard" access token
-/// key (default: "access_token").
-/// - If needed, use set_implicit_grant() to enable implicit grant flow.
-/// 2. Build authorization URI with build_authorization_uri() and open this in web browser/control.
-/// 3. The resource owner should then clicks "Yes" to authorize your client/app, and
-/// as a result the web browser/control is redirected to redirect_uri().
-/// 5. Capture the redirected URI either in web control or by HTTP listener.
-/// 6. Pass the redirected URI to token_from_redirected_uri() to obtain access token.
-/// - The method ensures redirected URI contains same state() as set in step 1.
-/// - In implicit_grant() is false, this will create HTTP request to fetch access token
-/// from the service. Otherwise access token is already included in the redirected URI.
-///
-/// Usage for issuing authenticated requests:
-/// 1. Perform authorization as above to obtain the access token or use an existing token.
-/// - Some services provide option to generate access tokens for testing purposes.
-/// 2. Pass the resulting oauth2_config with the access token to http_client_config::set_oauth2().
-/// 3. Construct http_client with this http_client_config. As a result, all HTTP requests
-/// by that client will be OAuth 2.0 authenticated.
-///
-///
-class oauth2_config
-{
-public:
-
- oauth2_config(utility::string_t client_key, utility::string_t client_secret,
- utility::string_t auth_endpoint, utility::string_t token_endpoint,
- utility::string_t redirect_uri, utility::string_t scope=utility::string_t()) :
- m_client_key(std::move(client_key)),
- m_client_secret(std::move(client_secret)),
- m_auth_endpoint(std::move(auth_endpoint)),
- m_token_endpoint(std::move(token_endpoint)),
- m_redirect_uri(std::move(redirect_uri)),
- m_scope(std::move(scope)),
- m_implicit_grant(false),
- m_bearer_auth(true),
- m_http_basic_auth(true),
- m_access_token_key(details::oauth2_strings::access_token)
- {}
-
- ///
- /// Builds an authorization URI to be loaded in the web browser/view.
- /// The URI is built with auth_endpoint() as basis.
- /// The implicit_grant() affects the built URI by selecting
- /// either authorization code or implicit grant flow.
- /// You can set generate_state to generate a new random state string.
- ///
- /// If true, a new random state() string is generated
- /// which replaces the current state(). If false, state() is unchanged and used as-is.
- /// Authorization URI string.
- _ASYNCRTIMP utility::string_t build_authorization_uri(bool generate_state);
-
- ///
- /// Fetch an access token (and possibly a refresh token) based on redirected URI.
- /// Behavior depends on the implicit_grant() setting.
- /// If implicit_grant() is false, the URI is parsed for 'code'
- /// parameter, and then token_from_code() is called with this code.
- /// See: http://tools.ietf.org/html/rfc6749#section-4.1
- /// Otherwise, redirect URI fragment part is parsed for 'access_token'
- /// parameter, which directly contains the token(s).
- /// See: http://tools.ietf.org/html/rfc6749#section-4.2
- /// In both cases, the 'state' parameter is parsed and is verified to match state().
- ///
- /// The URI where web browser/view was redirected after resource owner's authorization.
- /// Task that fetches the token(s) based on redirected URI.
- _ASYNCRTIMP pplx::task token_from_redirected_uri(const web::http::uri& redirected_uri);
-
- ///
- /// Fetches an access token (and possibly a refresh token) from the token endpoint.
- /// The task creates an HTTP request to the token_endpoint() which exchanges
- /// the authorization code for the token(s).
- /// This also sets the refresh token if one was returned.
- /// See: http://tools.ietf.org/html/rfc6749#section-4.1.3
- ///
- /// Code received via redirect upon successful authorization.
- /// Task that fetches token(s) based on the authorization code.
- pplx::task token_from_code(utility::string_t authorization_code)
- {
- uri_builder ub;
- ub.append_query(details::oauth2_strings::grant_type, details::oauth2_strings::authorization_code, false);
- ub.append_query(details::oauth2_strings::code, uri::encode_data_string(std::move(authorization_code)), false);
- ub.append_query(details::oauth2_strings::redirect_uri, uri::encode_data_string(redirect_uri()), false);
- return _request_token(ub);
- }
-
- ///
- /// Fetches a new access token (and possibly a new refresh token) using the refresh token.
- /// The task creates a HTTP request to the token_endpoint().
- /// If successful, resulting access token is set as active via set_token().
- /// See: http://tools.ietf.org/html/rfc6749#section-6
- /// This also sets a new refresh token if one was returned.
- ///
- /// Task that fetches the token(s) using the refresh token.
- pplx::task token_from_refresh()
- {
- uri_builder ub;
- ub.append_query(details::oauth2_strings::grant_type, details::oauth2_strings::refresh_token, false);
- ub.append_query(details::oauth2_strings::refresh_token, uri::encode_data_string(token().refresh_token()), false);
- return _request_token(ub);
- }
-
- ///
- /// Returns enabled state of the configuration.
- /// The oauth2_handler will perform OAuth 2.0 authentication only if
- /// this method returns true.
- /// Return value is true if access token is valid (=fetched or manually set).
- ///
- /// The configuration enabled state.
- bool is_enabled() const { return token().is_valid_access_token(); }
-
- ///
- /// Get client key.
- ///
- /// Client key string.
- const utility::string_t& client_key() const { return m_client_key; }
- ///
- /// Set client key.
- ///
- /// Client key string to set.
- void set_client_key(utility::string_t client_key) { m_client_key = std::move(client_key); }
-
- ///
- /// Get client secret.
- ///
- /// Client secret string.
- const utility::string_t& client_secret() const { return m_client_secret; }
- ///
- /// Set client secret.
- ///
- /// Client secret string to set.
- void set_client_secret(utility::string_t client_secret) { m_client_secret = std::move(client_secret); }
-
- ///
- /// Get authorization endpoint URI string.
- ///
- /// Authorization endpoint URI string.
- const utility::string_t& auth_endpoint() const { return m_auth_endpoint; }
- ///
- /// Set authorization endpoint URI string.
- ///
- /// Authorization endpoint URI string to set.
- void set_auth_endpoint(utility::string_t auth_endpoint) { m_auth_endpoint = std::move(auth_endpoint); }
-
- ///
- /// Get token endpoint URI string.
- ///
- /// Token endpoint URI string.
- const utility::string_t& token_endpoint() const { return m_token_endpoint; }
- ///
- /// Set token endpoint URI string.
- ///
- /// Token endpoint URI string to set.
- void set_token_endpoint(utility::string_t token_endpoint) { m_token_endpoint = std::move(token_endpoint); }
-
- ///
- /// Get redirect URI string.
- ///
- /// Redirect URI string.
- const utility::string_t& redirect_uri() const { return m_redirect_uri; }
- ///
- /// Set redirect URI string.
- ///
- /// Redirect URI string to set.
- void set_redirect_uri(utility::string_t redirect_uri) { m_redirect_uri = std::move(redirect_uri); }
-
- ///
- /// Get scope used in authorization for token.
- ///
- /// Scope string used in authorization.
- const utility::string_t& scope() const { return m_scope; }
- ///
- /// Set scope for authorization for token.
- ///
- /// Scope string for authorization for token.
- void set_scope(utility::string_t scope) { m_scope = std::move(scope); }
-
- ///
- /// Get client state string used in authorization.
- ///
- /// Client state string used in authorization.
- const utility::string_t& state() { return m_state; }
- ///
- /// Set client state string for authorization for token.
- /// The state string is used in authorization for security reasons
- /// (to uniquely identify authorization sessions).
- /// If desired, suitably secure state string can be automatically generated
- /// by build_authorization_uri().
- /// A good state string consist of 30 or more random alphanumeric characters.
- ///
- /// Client authorization state string to set.
- void set_state(utility::string_t state) { m_state = std::move(state); }
-
- ///
- /// Get token.
- ///
- /// Token.
- const oauth2_token& token() const { return m_token; }
- ///
- /// Set token.
- ///
- /// Token to set.
- void set_token(oauth2_token token) { m_token = std::move(token); }
-
- ///
- /// Get implicit grant setting for authorization.
- ///
- /// Implicit grant setting for authorization.
- bool implicit_grant() const { return m_implicit_grant; }
- ///
- /// Set implicit grant setting for authorization.
- /// False means authorization code grant is used for authorization.
- /// True means implicit grant is used.
- /// Default: False.
- ///
- /// The implicit grant setting to set.
- void set_implicit_grant(bool implicit_grant) { m_implicit_grant = implicit_grant; }
-
- ///
- /// Get bearer token authentication setting.
- ///
- /// Bearer token authentication setting.
- bool bearer_auth() const { return m_bearer_auth; }
- ///
- /// Set bearer token authentication setting.
- /// This must be selected based on what the service accepts.
- /// True means access token is passed in the request header. (http://tools.ietf.org/html/rfc6750#section-2.1)
- /// False means access token in passed in the query parameters. (http://tools.ietf.org/html/rfc6750#section-2.3)
- /// Default: True.
- ///
- /// The bearer token authentication setting to set.
- void set_bearer_auth(bool bearer_auth) { m_bearer_auth = bearer_auth; }
-
- ///
- /// Get HTTP Basic authentication setting for token endpoint.
- ///
- /// HTTP Basic authentication setting for token endpoint.
- bool http_basic_auth() const { return m_http_basic_auth; }
- ///
- /// Set HTTP Basic authentication setting for token endpoint.
- /// This setting must be selected based on what the service accepts.
- /// True means HTTP Basic authentication is used for the token endpoint.
- /// False means client key & secret are passed in the HTTP request body.
- /// Default: True.
- ///
- /// The HTTP Basic authentication setting to set.
- void set_http_basic_auth(bool http_basic_auth) { m_http_basic_auth = http_basic_auth; }
-
- ///
- /// Get access token key.
- ///
- /// Access token key string.
- const utility::string_t& access_token_key() const { return m_access_token_key; }
- ///
- /// Set access token key.
- /// If the service requires a "non-standard" key you must set it here.
- /// Default: "access_token".
- ///
- void set_access_token_key(utility::string_t access_token_key) { m_access_token_key = std::move(access_token_key); }
-
- ///
- /// Get the web proxy object
- ///
- /// A reference to the web proxy object.
- const web_proxy& proxy() const
- {
- return m_proxy;
- }
-
- ///
- /// Set the web proxy object that will be used by token_from_code and token_from_refresh
- ///
- /// A reference to the web proxy object.
- void set_proxy(const web_proxy& proxy)
- {
- m_proxy = proxy;
- }
-
-private:
- friend class web::http::client::http_client_config;
- friend class web::http::oauth2::details::oauth2_handler;
-
- oauth2_config() :
- m_implicit_grant(false),
- m_bearer_auth(true),
- m_http_basic_auth(true)
- {}
-
- _ASYNCRTIMP pplx::task _request_token(uri_builder& request_body);
-
- oauth2_token _parse_token_from_json(const json::value& token_json);
-
- void _authenticate_request(http_request &req) const
- {
- if (bearer_auth())
- {
- req.headers().add(header_names::authorization, _XPLATSTR("Bearer ") + token().access_token());
- }
- else
- {
- uri_builder ub(req.request_uri());
- ub.append_query(access_token_key(), token().access_token());
- req.set_request_uri(ub.to_uri());
- }
- }
-
- utility::string_t m_client_key;
- utility::string_t m_client_secret;
- utility::string_t m_auth_endpoint;
- utility::string_t m_token_endpoint;
- utility::string_t m_redirect_uri;
- utility::string_t m_scope;
- utility::string_t m_state;
-
- web::web_proxy m_proxy;
-
- bool m_implicit_grant;
- bool m_bearer_auth;
- bool m_http_basic_auth;
- utility::string_t m_access_token_key;
-
- oauth2_token m_token;
-
- utility::nonce_generator m_state_generator;
-};
-
-} // namespace web::http::oauth2::experimental
-
-namespace details
-{
-
-class oauth2_handler : public http_pipeline_stage
-{
-public:
- oauth2_handler(std::shared_ptr cfg) :
- m_config(std::move(cfg))
- {}
-
- virtual pplx::task propagate(http_request request) override
- {
- if (m_config)
- {
- m_config->_authenticate_request(request);
+ };
+
+ } // namespace web::http::oauth2::details
+
+ /// oAuth functionality is currently in beta.
+ namespace experimental {
+
+ ///
+ /// Exception type for OAuth 2.0 errors.
+ ///
+ class oauth2_exception : public std::exception {
+ public:
+ oauth2_exception(utility::string_t msg)
+ : m_msg(utility::conversions::to_utf8string(std::move(msg)))
+ {
+ }
+ ~oauth2_exception() CPPREST_NOEXCEPT {}
+ const char* what() const CPPREST_NOEXCEPT
+ {
+ return m_msg.c_str();
+ }
+
+ private:
+ std::string m_msg;
+ };
+
+ ///
+ /// OAuth 2.0 token and associated information.
+ ///
+ class oauth2_token {
+ public:
+ ///
+ /// Value for undefined expiration time in expires_in().
+ ///
+ enum { undefined_expiration = -1 };
+
+ oauth2_token(
+ utility::string_t access_token = utility::string_t())
+ : m_access_token(std::move(access_token))
+ , m_expires_in(undefined_expiration)
+ {
+ }
+
+ ///
+ /// Get access token validity state.
+ /// If true, access token is a valid.
+ ///
+ /// Access token validity state.
+ bool is_valid_access_token() const
+ {
+ return !access_token().empty();
+ }
+
+ ///
+ /// Get access token.
+ ///
+ /// Access token string.
+ const utility::string_t& access_token() const
+ {
+ return m_access_token;
+ }
+ ///
+ /// Set access token.
+ ///
+ /// Access token string to
+ /// set.
+ void set_access_token(utility::string_t access_token)
+ {
+ m_access_token = std::move(access_token);
+ }
+
+ ///
+ /// Get refresh token.
+ ///
+ /// Refresh token string.
+ const utility::string_t& refresh_token() const
+ {
+ return m_refresh_token;
+ }
+ ///
+ /// Set refresh token.
+ ///
+ /// Refresh token string to
+ /// set.
+ void set_refresh_token(utility::string_t refresh_token)
+ {
+ m_refresh_token = std::move(refresh_token);
+ }
+
+ ///
+ /// Get token type.
+ ///
+ /// Token type string.
+ const utility::string_t& token_type() const
+ {
+ return m_token_type;
+ }
+ ///
+ /// Set token type.
+ ///
+ /// Token type string to set.
+ void set_token_type(utility::string_t token_type)
+ {
+ m_token_type = std::move(token_type);
+ }
+
+ ///
+ /// Get token scope.
+ ///
+ /// Token scope string.
+ const utility::string_t& scope() const { return m_scope; }
+ ///
+ /// Set token scope.
+ ///
+ /// Token scope string to set.
+ void set_scope(utility::string_t scope)
+ {
+ m_scope = std::move(scope);
+ }
+
+ ///
+ /// Get the lifetime of the access token in seconds.
+ /// For example, 3600 means the access token will expire in one
+ /// hour from
+ /// the time when access token response was generated by the
+ /// authorization server.
+ /// Value of undefined_expiration means expiration time is
+ /// either
+ /// unset or that it was not returned by the server with the
+ /// access token.
+ ///
+ /// Lifetime of the access token in seconds or
+ /// undefined_expiration if not set.
+ int64_t expires_in() const { return m_expires_in; }
+ ///
+ /// Set lifetime of access token (in seconds).
+ ///
+ /// Lifetime of access token in
+ /// seconds.
+ void set_expires_in(int64_t expires_in)
+ {
+ m_expires_in = expires_in;
+ }
+
+ private:
+ utility::string_t m_access_token;
+ utility::string_t m_refresh_token;
+ utility::string_t m_token_type;
+ utility::string_t m_scope;
+ int64_t m_expires_in;
+ };
+
+ ///
+ /// OAuth 2.0 configuration.
+ ///
+ /// Encapsulates functionality for:
+ /// - Authenticating requests with an access token.
+ /// - Performing the OAuth 2.0 authorization code grant
+ /// authorization flow.
+ /// See: http://tools.ietf.org/html/rfc6749#section-4.1
+ /// - Performing the OAuth 2.0 implicit grant authorization flow.
+ /// See: http://tools.ietf.org/html/rfc6749#section-4.2
+ ///
+ /// Performing OAuth 2.0 authorization:
+ /// 1. Set service and client/app parameters:
+ /// - Client/app key & secret (as provided by the service).
+ /// - The service authorization endpoint and token endpoint.
+ /// - Your client/app redirect URI.
+ /// - Use set_state() to assign a unique state string for the
+ /// authorization
+ /// session (default: "").
+ /// - If needed, use set_bearer_auth() to control bearer token
+ /// passing in either
+ /// query or header (default: header). See:
+ /// http://tools.ietf.org/html/rfc6750#section-2
+ /// - If needed, use set_access_token_key() to set "non-standard"
+ /// access token
+ /// key (default: "access_token").
+ /// - If needed, use set_implicit_grant() to enable implicit grant
+ /// flow.
+ /// 2. Build authorization URI with build_authorization_uri() and
+ /// open this in web browser/control.
+ /// 3. The resource owner should then clicks "Yes" to authorize your
+ /// client/app, and
+ /// as a result the web browser/control is redirected to
+ /// redirect_uri().
+ /// 5. Capture the redirected URI either in web control or by HTTP
+ /// listener.
+ /// 6. Pass the redirected URI to token_from_redirected_uri() to
+ /// obtain access token.
+ /// - The method ensures redirected URI contains same state() as
+ /// set in step 1.
+ /// - In implicit_grant() is false, this will create HTTP request
+ /// to fetch access token
+ /// from the service. Otherwise access token is already included
+ /// in the redirected URI.
+ ///
+ /// Usage for issuing authenticated requests:
+ /// 1. Perform authorization as above to obtain the access token or
+ /// use an existing token.
+ /// - Some services provide option to generate access tokens for
+ /// testing purposes.
+ /// 2. Pass the resulting oauth2_config with the access token to
+ /// http_client_config::set_oauth2().
+ /// 3. Construct http_client with this http_client_config. As a
+ /// result, all HTTP requests
+ /// by that client will be OAuth 2.0 authenticated.
+ ///
+ ///
+ class oauth2_config {
+ public:
+ oauth2_config(utility::string_t client_key,
+ utility::string_t client_secret,
+ utility::string_t auth_endpoint,
+ utility::string_t token_endpoint,
+ utility::string_t redirect_uri,
+ utility::string_t scope = utility::string_t())
+ : m_client_key(std::move(client_key))
+ , m_client_secret(std::move(client_secret))
+ , m_auth_endpoint(std::move(auth_endpoint))
+ , m_token_endpoint(std::move(token_endpoint))
+ , m_redirect_uri(std::move(redirect_uri))
+ , m_scope(std::move(scope))
+ , m_implicit_grant(false)
+ , m_bearer_auth(true)
+ , m_http_basic_auth(true)
+ , m_access_token_key(details::oauth2_strings::access_token)
+ {
+ }
+
+ ///
+ /// Builds an authorization URI to be loaded in the web
+ /// browser/view.
+ /// The URI is built with auth_endpoint() as basis.
+ /// The implicit_grant() affects the built URI by selecting
+ /// either authorization code or implicit grant flow.
+ /// You can set generate_state to generate a new random state
+ /// string.
+ ///
+ /// If true, a new random state()
+ /// string is generated
+ /// which replaces the current state(). If false, state() is
+ /// unchanged and used as-is.
+ /// Authorization URI string.
+ _ASYNCRTIMP utility::string_t build_authorization_uri(
+ bool generate_state);
+
+ ///
+ /// Fetch an access token (and possibly a refresh token) based
+ /// on redirected URI.
+ /// Behavior depends on the implicit_grant() setting.
+ /// If implicit_grant() is false, the URI is parsed for 'code'
+ /// parameter, and then token_from_code() is called with this
+ /// code.
+ /// See: http://tools.ietf.org/html/rfc6749#section-4.1
+ /// Otherwise, redirect URI fragment part is parsed for
+ /// 'access_token'
+ /// parameter, which directly contains the token(s).
+ /// See: http://tools.ietf.org/html/rfc6749#section-4.2
+ /// In both cases, the 'state' parameter is parsed and is
+ /// verified to match state().
+ ///
+ /// The URI where web browser/view
+ /// was redirected after resource owner's authorization.
+ /// Task that fetches the token(s) based on redirected
+ /// URI.
+ _ASYNCRTIMP pplx::task token_from_redirected_uri(
+ const web::http::uri& redirected_uri);
+
+ ///
+ /// Fetches an access token (and possibly a refresh token) from
+ /// the token endpoint.
+ /// The task creates an HTTP request to the token_endpoint()
+ /// which exchanges
+ /// the authorization code for the token(s).
+ /// This also sets the refresh token if one was returned.
+ /// See: http://tools.ietf.org/html/rfc6749#section-4.1.3
+ ///
+ /// Code received via redirect
+ /// upon successful authorization.
+ /// Task that fetches token(s) based on the
+ /// authorization code.
+ pplx::task token_from_code(
+ utility::string_t authorization_code)
+ {
+ uri_builder ub;
+ ub.append_query(details::oauth2_strings::grant_type,
+ details::oauth2_strings::authorization_code, false);
+ ub.append_query(details::oauth2_strings::code,
+ uri::encode_data_string(std::move(authorization_code)),
+ false);
+ ub.append_query(details::oauth2_strings::redirect_uri,
+ uri::encode_data_string(redirect_uri()), false);
+ return _request_token(ub);
+ }
+
+ ///
+ /// Fetches a new access token (and possibly a new refresh
+ /// token) using the refresh token.
+ /// The task creates a HTTP request to the token_endpoint().
+ /// If successful, resulting access token is set as active via
+ /// set_token().
+ /// See: http://tools.ietf.org/html/rfc6749#section-6
+ /// This also sets a new refresh token if one was returned.
+ ///
+ /// Task that fetches the token(s) using the refresh
+ /// token.
+ pplx::task token_from_refresh()
+ {
+ uri_builder ub;
+ ub.append_query(details::oauth2_strings::grant_type,
+ details::oauth2_strings::refresh_token, false);
+ ub.append_query(details::oauth2_strings::refresh_token,
+ uri::encode_data_string(token().refresh_token()),
+ false);
+ return _request_token(ub);
+ }
+
+ ///
+ /// Returns enabled state of the configuration.
+ /// The oauth2_handler will perform OAuth 2.0 authentication
+ /// only if
+ /// this method returns true.
+ /// Return value is true if access token is valid (=fetched or
+ /// manually set).
+ ///
+ /// The configuration enabled state.
+ bool is_enabled() const
+ {
+ return token().is_valid_access_token();
+ }
+
+ ///
+ /// Get client key.
+ ///
+ /// Client key string.
+ const utility::string_t& client_key() const
+ {
+ return m_client_key;
+ }
+ ///
+ /// Set client key.
+ ///
+ /// Client key string to set.
+ void set_client_key(utility::string_t client_key)
+ {
+ m_client_key = std::move(client_key);
+ }
+
+ ///
+ /// Get client secret.
+ ///
+ /// Client secret string.
+ const utility::string_t& client_secret() const
+ {
+ return m_client_secret;
+ }
+ ///
+ /// Set client secret.
+ ///
+ /// Client secret string to
+ /// set.
+ void set_client_secret(utility::string_t client_secret)
+ {
+ m_client_secret = std::move(client_secret);
+ }
+
+ ///
+ /// Get authorization endpoint URI string.
+ ///
+ /// Authorization endpoint URI string.
+ const utility::string_t& auth_endpoint() const
+ {
+ return m_auth_endpoint;
+ }
+ ///
+ /// Set authorization endpoint URI string.
+ ///
+ /// Authorization endpoint URI
+ /// string to set.
+ void set_auth_endpoint(utility::string_t auth_endpoint)
+ {
+ m_auth_endpoint = std::move(auth_endpoint);
+ }
+
+ ///
+ /// Get token endpoint URI string.
+ ///
+ /// Token endpoint URI string.
+ const utility::string_t& token_endpoint() const
+ {
+ return m_token_endpoint;
+ }
+ ///
+ /// Set token endpoint URI string.
+ ///
+ /// Token endpoint URI string to
+ /// set.
+ void set_token_endpoint(utility::string_t token_endpoint)
+ {
+ m_token_endpoint = std::move(token_endpoint);
+ }
+
+ ///
+ /// Get redirect URI string.
+ ///
+ /// Redirect URI string.
+ const utility::string_t& redirect_uri() const
+ {
+ return m_redirect_uri;
+ }
+ ///
+ /// Set redirect URI string.
+ ///
+ /// Redirect URI string to
+ /// set.
+ void set_redirect_uri(utility::string_t redirect_uri)
+ {
+ m_redirect_uri = std::move(redirect_uri);
+ }
+
+ ///
+ /// Get scope used in authorization for token.
+ ///
+ /// Scope string used in authorization.
+ const utility::string_t& scope() const { return m_scope; }
+ ///
+ /// Set scope for authorization for token.
+ ///
+ /// Scope string for authorization for
+ /// token.
+ void set_scope(utility::string_t scope)
+ {
+ m_scope = std::move(scope);
+ }
+
+ ///
+ /// Get client state string used in authorization.
+ ///
+ /// Client state string used in
+ /// authorization.
+ const utility::string_t& state() { return m_state; }
+ ///
+ /// Set client state string for authorization for token.
+ /// The state string is used in authorization for security
+ /// reasons
+ /// (to uniquely identify authorization sessions).
+ /// If desired, suitably secure state string can be
+ /// automatically generated
+ /// by build_authorization_uri().
+ /// A good state string consist of 30 or more random
+ /// alphanumeric characters.
+ ///
+ /// Client authorization state string to
+ /// set.
+ void set_state(utility::string_t state)
+ {
+ m_state = std::move(state);
+ }
+
+ ///
+ /// Get token.
+ ///
+ /// Token.
+ const oauth2_token& token() const { return m_token; }
+ ///
+ /// Set token.
+ ///
+ /// Token to set.
+ void set_token(oauth2_token token)
+ {
+ m_token = std::move(token);
+ }
+
+ ///
+ /// Get implicit grant setting for authorization.
+ ///
+ /// Implicit grant setting for authorization.
+ bool implicit_grant() const { return m_implicit_grant; }
+ ///
+ /// Set implicit grant setting for authorization.
+ /// False means authorization code grant is used for
+ /// authorization.
+ /// True means implicit grant is used.
+ /// Default: False.
+ ///
+ /// The implicit grant setting to
+ /// set.
+ void set_implicit_grant(bool implicit_grant)
+ {
+ m_implicit_grant = implicit_grant;
+ }
+
+ ///
+ /// Get bearer token authentication setting.
+ ///
+ /// Bearer token authentication setting.
+ bool bearer_auth() const { return m_bearer_auth; }
+ ///
+ /// Set bearer token authentication setting.
+ /// This must be selected based on what the service accepts.
+ /// True means access token is passed in the request header.
+ /// (http://tools.ietf.org/html/rfc6750#section-2.1)
+ /// False means access token in passed in the query parameters.
+ /// (http://tools.ietf.org/html/rfc6750#section-2.3)
+ /// Default: True.
+ ///
+ /// The bearer token authentication
+ /// setting to set.
+ void set_bearer_auth(bool bearer_auth)
+ {
+ m_bearer_auth = bearer_auth;
+ }
+
+ ///
+ /// Get HTTP Basic authentication setting for token endpoint.
+ ///
+ /// HTTP Basic authentication setting for token
+ /// endpoint.
+ bool http_basic_auth() const { return m_http_basic_auth; }
+ ///
+ /// Set HTTP Basic authentication setting for token endpoint.
+ /// This setting must be selected based on what the service
+ /// accepts.
+ /// True means HTTP Basic authentication is used for the token
+ /// endpoint.
+ /// False means client key & secret are passed in the HTTP
+ /// request body.
+ /// Default: True.
+ ///
+ /// The HTTP Basic authentication
+ /// setting to set.
+ void set_http_basic_auth(bool http_basic_auth)
+ {
+ m_http_basic_auth = http_basic_auth;
+ }
+
+ ///
+ /// Get access token key.
+ ///
+ /// Access token key string.
+ const utility::string_t& access_token_key() const
+ {
+ return m_access_token_key;
+ }
+ ///
+ /// Set access token key.
+ /// If the service requires a "non-standard" key you must set it
+ /// here.
+ /// Default: "access_token".
+ ///
+ void set_access_token_key(utility::string_t access_token_key)
+ {
+ m_access_token_key = std::move(access_token_key);
+ }
+
+ ///
+ /// Get the web proxy object
+ ///
+ /// A reference to the web proxy object.
+ const web_proxy& proxy() const { return m_proxy; }
+
+ ///
+ /// Set the web proxy object that will be used by
+ /// token_from_code and token_from_refresh
+ ///
+ /// A reference to the web proxy
+ /// object.
+ void set_proxy(const web_proxy& proxy) { m_proxy = proxy; }
+
+ private:
+ friend class web::http::client::http_client_config;
+ friend class web::http::oauth2::details::oauth2_handler;
+
+ oauth2_config()
+ : m_implicit_grant(false)
+ , m_bearer_auth(true)
+ , m_http_basic_auth(true)
+ {
+ }
+
+ _ASYNCRTIMP pplx::task _request_token(
+ uri_builder& request_body);
+
+ oauth2_token _parse_token_from_json(
+ const json::value& token_json);
+
+ void _authenticate_request(http_request& req) const
+ {
+ if (bearer_auth()) {
+ req.headers().add(header_names::authorization,
+ _XPLATSTR("Bearer ") + token().access_token());
+ }
+ else {
+ uri_builder ub(req.request_uri());
+ ub.append_query(
+ access_token_key(), token().access_token());
+ req.set_request_uri(ub.to_uri());
+ }
+ }
+
+ utility::string_t m_client_key;
+ utility::string_t m_client_secret;
+ utility::string_t m_auth_endpoint;
+ utility::string_t m_token_endpoint;
+ utility::string_t m_redirect_uri;
+ utility::string_t m_scope;
+ utility::string_t m_state;
+
+ web::web_proxy m_proxy;
+
+ bool m_implicit_grant;
+ bool m_bearer_auth;
+ bool m_http_basic_auth;
+ utility::string_t m_access_token_key;
+
+ oauth2_token m_token;
+
+ utility::nonce_generator m_state_generator;
+ };
+
+ } // namespace web::http::oauth2::experimental
+
+ namespace details {
+
+ class oauth2_handler : public http_pipeline_stage {
+ public:
+ oauth2_handler(std::shared_ptr cfg)
+ : m_config(std::move(cfg))
+ {
+ }
+
+ virtual pplx::task propagate(
+ http_request request) override
+ {
+ if (m_config) {
+ m_config->_authenticate_request(request);
+ }
+ return next_stage()->propagate(request);
+ }
+
+ private:
+ std::shared_ptr m_config;
+ };
}
- return next_stage()->propagate(request);
}
-
-private:
- std::shared_ptr m_config;
-};
-
-}}}}
+}
+}
#endif