-- | This module contains a new way of doing OAuth2 authorization and authentication -- in order to obtain Access Token and maybe Refresh Token base on rfc6749. -- -- This module will become default in future release. -- -- The key concept/change is to introduce the Grant flow, which determines the entire work flow per spec. -- Each work flow will have slight different request parameters, which often time you'll see -- different configuration when creating OAuth2 application in the IdP developer application page. -- -- Here are supported flows -- -- 1. Authorization Code. This flow requires authorize call to obtain an authorize code, -- then exchange the code for tokens. -- -- 2. Resource Owner Password. This flow only requires to hit token endpoint with, of course, -- username and password, to obtain tokens. -- -- 3. Client Credentials. This flow also only requires to hit token endpoint but with different parameters. -- Client credentials flow does not involve an end user hence you won't be able to hit userinfo endpoint -- with access token obtained. -- -- 5. PKCE (rfc7636). This is enhancement on top of authorization code flow. -- -- Implicit flow is not supported because it is more for SPA (single page app) -- given it is deprecated by Authorization Code flow with PKCE. -- -- Here is quick sample for how to use vocabularies from this new module. -- -- Firstly, initialize your IdP (use google as example) and the application. -- -- @ -- -- import Network.OAuth2.Experiment -- import URI.ByteString.QQ -- -- data Google = Google deriving (Eq, Show) -- -- googleIdp :: Idp Google -- googleIdp = -- Idp -- { idpAuthorizeEndpoint = [uri|https:\/\/accounts.google.com\/o\/oauth2\/v2\/auth|] -- , idpTokenEndpoint = [uri|https:\/\/oauth2.googleapis.com\/token|] -- , idpUserInfoEndpoint = [uri|https:\/\/www.googleapis.com\/oauth2\/v2\/userinfo|] -- , idpDeviceAuthorizationEndpoint = Just [uri|https:\/\/oauth2.googleapis.com\/device\/code|] -- } -- -- fooApp :: AuthorizationCodeApplication -- fooApp = -- AuthorizationCodeApplication -- { acClientId = "xxxxx", -- acClientSecret = "xxxxx", -- acScope = -- Set.fromList -- [ \"https:\/\/www.googleapis.com\/auth\/userinfo.email\", -- \"https:\/\/www.googleapis.com\/auth\/userinfo.profile\" -- ], -- acAuthorizeState = \"CHANGE_ME\", -- acAuthorizeRequestExtraParams = Map.empty, -- acRedirectUri = [uri|http:\/\/localhost\/oauth2\/callback|], -- acName = "sample-google-authorization-code-app", -- acTokenRequestAuthenticationMethod = ClientSecretBasic, -- } -- -- fooIdpApplication :: IdpApplication AuthorizationCodeApplication Google -- fooIdpApplication = IdpApplication fooApp googleIdp -- @ -- -- Secondly, construct the authorize URL. -- -- @ -- authorizeUrl = mkAuthorizationRequest fooIdpApplication -- @ -- -- Thirdly, after a successful redirect with authorize code, -- you could exchange for access token -- -- @ -- mgr <- liftIO $ newManager tlsManagerSettings -- tokenResp <- conduitTokenRequest fooIdpApplication mgr authorizeCode -- @ -- -- If you'd like to fetch user info, uses this method -- -- @ -- conduitUserInfoRequest fooIdpApplication mgr (accessToken tokenResp) -- @ -- -- You could also find example from @hoauth2-providers-tutorials@ module. module Network.OAuth2.Experiment ( -- * Application per Grant type module Network.OAuth2.Experiment.Grants, -- * Authorization Code module Network.OAuth2.Experiment.Flows.AuthorizationRequest, -- * Device Authorization module Network.OAuth2.Experiment.Flows.DeviceAuthorizationRequest, -- * Token Request module Network.OAuth2.Experiment.Flows.TokenRequest, -- * Refresh Token Request module Network.OAuth2.Experiment.Flows.RefreshTokenRequest, -- * UserInfo Request module Network.OAuth2.Experiment.Flows.UserInfoRequest, -- * Types module Network.OAuth2.Experiment.Types, module Network.OAuth2.Experiment.Pkce, module Network.OAuth.OAuth2, -- * Utils module Network.OAuth2.Experiment.Utils, ) where import Network.OAuth.OAuth2 (ClientAuthenticationMethod (..)) import Network.OAuth2.Experiment.Flows.AuthorizationRequest ( HasAuthorizeRequest, mkAuthorizationRequest, mkPkceAuthorizeRequest, ) import Network.OAuth2.Experiment.Flows.DeviceAuthorizationRequest ( DeviceAuthorizationResponse (..), HasDeviceAuthorizationRequest, conduitDeviceAuthorizationRequest, ) import Network.OAuth2.Experiment.Flows.RefreshTokenRequest ( HasRefreshTokenRequest, conduitRefreshTokenRequest, ) import Network.OAuth2.Experiment.Flows.TokenRequest ( ExchangeTokenInfo, HasTokenRequest, NoNeedExchangeToken (..), TokenRequest, conduitPkceTokenRequest, conduitTokenRequest, ) import Network.OAuth2.Experiment.Flows.UserInfoRequest ( HasUserInfoRequest, conduitUserInfoRequest, conduitUserInfoRequestWithCustomMethod, ) import Network.OAuth2.Experiment.Grants import Network.OAuth2.Experiment.Pkce ( CodeVerifier (..), ) import Network.OAuth2.Experiment.Types ( AuthorizeState (..), ClientId (..), ClientSecret (..), HasOAuth2Key, Idp (..), IdpApplication (..), Password (..), RedirectUri (..), Scope (..), Username (..), ) import Network.OAuth2.Experiment.Utils (uriToText)