-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Haskell OAuth2 authentication client -- -- This is Haskell binding of OAuth2 Authorization framework and Bearer -- Token Usage framework. @package hoauth2 @version 2.12.0 module Network.OAuth2.Experiment.Pkce mkPkceParam :: MonadIO m => m PkceRequestParam newtype CodeChallenge CodeChallenge :: Text -> CodeChallenge [unCodeChallenge] :: CodeChallenge -> Text newtype CodeVerifier CodeVerifier :: Text -> CodeVerifier [unCodeVerifier] :: CodeVerifier -> Text data CodeChallengeMethod S256 :: CodeChallengeMethod data PkceRequestParam PkceRequestParam :: CodeVerifier -> CodeChallenge -> CodeChallengeMethod -> PkceRequestParam [codeVerifier] :: PkceRequestParam -> CodeVerifier [codeChallenge] :: PkceRequestParam -> CodeChallenge -- | spec says optional but in practice it is S256 -- https://datatracker.ietf.org/doc/html/rfc7636#section-4.3 [codeChallengeMethod] :: PkceRequestParam -> CodeChallengeMethod instance GHC.Show.Show Network.OAuth2.Experiment.Pkce.CodeChallengeMethod -- | Bindings Access Token and Refresh Token part of The OAuth 2.0 -- Authorization Framework RFC6749 -- https://www.rfc-editor.org/rfc/rfc6749 module Network.OAuth.OAuth2.TokenRequest data TokenResponseError TokenResponseError :: TokenResponseErrorCode -> Maybe Text -> Maybe (URIRef Absolute) -> TokenResponseError [tokenResponseError] :: TokenResponseError -> TokenResponseErrorCode [tokenResponseErrorDescription] :: TokenResponseError -> Maybe Text [tokenResponseErrorUri] :: TokenResponseError -> Maybe (URIRef Absolute) -- | Token Error Responses -- https://tools.ietf.org/html/rfc6749#section-5.2 data TokenResponseErrorCode InvalidRequest :: TokenResponseErrorCode InvalidClient :: TokenResponseErrorCode InvalidGrant :: TokenResponseErrorCode UnauthorizedClient :: TokenResponseErrorCode UnsupportedGrantType :: TokenResponseErrorCode InvalidScope :: TokenResponseErrorCode UnknownErrorCode :: Text -> TokenResponseErrorCode parseTokeResponseError :: ByteString -> TokenResponseError -- | Prepare the URL and the request body query for fetching an access -- token. accessTokenUrl :: OAuth2 -> ExchangeToken -> (URI, PostBody) -- | Obtain a new access token by sending a Refresh Token to the -- Authorization server. refreshAccessTokenUrl :: OAuth2 -> RefreshToken -> (URI, PostBody) -- | Exchange code for an Access Token with authenticate in -- request header. fetchAccessToken :: MonadIO m => Manager -> OAuth2 -> ExchangeToken -> ExceptT TokenResponseError m OAuth2Token -- | Deprecated: use fetchAccessTokenWithAuthMethod fetchAccessToken2 :: MonadIO m => Manager -> OAuth2 -> ExchangeToken -> ExceptT TokenResponseError m OAuth2Token -- | Deprecated: use fetchAccessTokenWithAuthMethod fetchAccessTokenInternal :: MonadIO m => ClientAuthenticationMethod -> Manager -> OAuth2 -> ExchangeToken -> ExceptT TokenResponseError m OAuth2Token -- | Exchange code for an Access Token -- -- OAuth2 spec allows credential (client_id, -- client_secret) to be sent either in the header (a.k.a -- ClientSecretBasic). or as form/url params (a.k.a -- ClientSecretPost). -- -- The OAuth provider can choose to implement only one, or both. Look for -- API document from the OAuth provider you're dealing with. If you`re -- uncertain, try fetchAccessToken which sends credential in -- authorization http header, which is common case. fetchAccessTokenWithAuthMethod :: MonadIO m => ClientAuthenticationMethod -> Manager -> OAuth2 -> ExchangeToken -> ExceptT TokenResponseError m OAuth2Token -- | Fetch a new AccessToken using the Refresh Token with authentication in -- request header. refreshAccessToken :: MonadIO m => Manager -> OAuth2 -> RefreshToken -> ExceptT TokenResponseError m OAuth2Token -- | Deprecated: use refreshAccessTokenWithAuthMethod refreshAccessToken2 :: MonadIO m => Manager -> OAuth2 -> RefreshToken -> ExceptT TokenResponseError m OAuth2Token -- | Deprecated: use refreshAccessTokenWithAuthMethod refreshAccessTokenInternal :: MonadIO m => ClientAuthenticationMethod -> Manager -> OAuth2 -> RefreshToken -> ExceptT TokenResponseError m OAuth2Token -- | Fetch a new AccessToken using the Refresh Token. -- -- OAuth2 spec allows credential ("client_id", "client_secret") to be -- sent either in the header (a.k.a ClientSecretBasic). or as -- form/url params (a.k.a ClientSecretPost). -- -- The OAuth provider can choose to implement only one, or both. Look for -- API document from the OAuth provider you're dealing with. If you're -- uncertain, try refreshAccessToken which sends credential in -- authorization http header, which is common case. refreshAccessTokenWithAuthMethod :: MonadIO m => ClientAuthenticationMethod -> Manager -> OAuth2 -> RefreshToken -> ExceptT TokenResponseError m OAuth2Token -- | Conduct post request and return response as JSON. doJSONPostRequest :: (MonadIO m, FromJSON a) => Manager -> OAuth2 -> URI -> PostBody -> ExceptT TokenResponseError m a -- | Conduct post request. doSimplePostRequest :: MonadIO m => Manager -> OAuth2 -> URI -> PostBody -> ExceptT TokenResponseError m ByteString -- | Gets response body from a Response if 200 otherwise assume -- TokenResponseError handleOAuth2TokenResponse :: Response ByteString -> Either TokenResponseError ByteString -- | Try to parses response as JSON, if failed, try to parse as like query -- string. parseResponseFlexible :: FromJSON a => ByteString -> Either TokenResponseError a -- | Parses the response that contains not JSON but a Query String parseResponseString :: FromJSON a => ByteString -> Either TokenResponseError a -- | Add Basic Authentication header using client_id and client_secret. addBasicAuth :: OAuth2 -> Request -> Request -- | Set several header values: + userAgennt : "hoauth2" + accept : -- "application/json" addDefaultRequestHeaders :: Request -> Request -- | Add Credential (client_id, client_secret) to the request post body. clientSecretPost :: OAuth2 -> PostBody instance GHC.Classes.Eq Network.OAuth.OAuth2.TokenRequest.TokenResponseErrorCode instance GHC.Show.Show Network.OAuth.OAuth2.TokenRequest.TokenResponseErrorCode instance GHC.Classes.Eq Network.OAuth.OAuth2.TokenRequest.TokenResponseError instance GHC.Show.Show Network.OAuth.OAuth2.TokenRequest.TokenResponseError instance Data.Aeson.Types.FromJSON.FromJSON Network.OAuth.OAuth2.TokenRequest.TokenResponseError instance Data.Aeson.Types.FromJSON.FromJSON Network.OAuth.OAuth2.TokenRequest.TokenResponseErrorCode -- | Bindings for The OAuth 2.0 Authorization Framework: Bearer Token Usage -- RFC6750 https://www.rfc-editor.org/rfc/rfc6750 module Network.OAuth.OAuth2.HttpClient -- | Conduct an authorized GET request and return response as JSON. Inject -- Access Token to Authorization Header. authGetJSON :: (MonadIO m, FromJSON a) => Manager -> AccessToken -> URI -> ExceptT ByteString m a -- | Conduct an authorized GET request. Inject Access Token to -- Authorization Header. authGetBS :: MonadIO m => Manager -> AccessToken -> URI -> ExceptT ByteString m ByteString -- | Same to authGetBS but set access token to query parameter -- rather than header -- | Deprecated: use authGetBSWithAuthMethod authGetBS2 :: MonadIO m => Manager -> AccessToken -> URI -> ExceptT ByteString m ByteString -- | Conduct an authorized GET request and return response as JSON. Allow -- to specify how to append AccessToken. authGetJSONWithAuthMethod :: (MonadIO m, FromJSON a) => APIAuthenticationMethod -> Manager -> AccessToken -> URI -> ExceptT ByteString m a -- | Deprecated. Use authGetJSONWithAuthMethod instead. -- | Deprecated: use authGetJSONWithAuthMethod authGetJSONInternal :: (MonadIO m, FromJSON a) => APIAuthenticationMethod -> Manager -> AccessToken -> URI -> ExceptT ByteString m a -- | Conduct an authorized GET request and return response as ByteString. -- Allow to specify how to append AccessToken. authGetBSWithAuthMethod :: MonadIO m => APIAuthenticationMethod -> Manager -> AccessToken -> URI -> ExceptT ByteString m ByteString -- | Deprecated: use authGetBSWithAuthMethod authGetBSInternal :: MonadIO m => APIAuthenticationMethod -> Manager -> AccessToken -> URI -> ExceptT ByteString m ByteString -- | Conduct POST request and return response as JSON. Inject Access Token -- to Authorization Header. authPostJSON :: (MonadIO m, FromJSON a) => Manager -> AccessToken -> URI -> PostBody -> ExceptT ByteString m a -- | Conduct POST request. Inject Access Token to http header -- (Authorization) authPostBS :: MonadIO m => Manager -> AccessToken -> URI -> PostBody -> ExceptT ByteString m ByteString -- | Conduct POST request with access token only in the request body but -- header. -- | Deprecated: use authPostBSWithAuthMethod authPostBS2 :: MonadIO m => Manager -> AccessToken -> URI -> PostBody -> ExceptT ByteString m ByteString -- | Conduct POST request with access token only in the header and not in -- body -- | Deprecated: use authPostBSWithAuthMethod authPostBS3 :: MonadIO m => Manager -> AccessToken -> URI -> PostBody -> ExceptT ByteString m ByteString -- | Conduct POST request and return response as JSON. Allow to specify how -- to append AccessToken. authPostJSONWithAuthMethod :: (MonadIO m, FromJSON a) => APIAuthenticationMethod -> Manager -> AccessToken -> URI -> PostBody -> ExceptT ByteString m a -- | Deprecated: use authPostJSONWithAuthMethod authPostJSONInternal :: (MonadIO m, FromJSON a) => APIAuthenticationMethod -> Manager -> AccessToken -> URI -> PostBody -> ExceptT ByteString m a -- | Conduct POST request and return response as ByteString. Allow to -- specify how to append AccessToken. authPostBSWithAuthMethod :: MonadIO m => APIAuthenticationMethod -> Manager -> AccessToken -> URI -> PostBody -> ExceptT ByteString m ByteString -- | Deprecated: use authPostBSWithAuthMethod authPostBSInternal :: MonadIO m => APIAuthenticationMethod -> Manager -> AccessToken -> URI -> PostBody -> ExceptT ByteString m ByteString -- | https://www.rfc-editor.org/rfc/rfc6750#section-2 data APIAuthenticationMethod -- | Provides in Authorization header AuthInRequestHeader :: APIAuthenticationMethod -- | Provides in request body AuthInRequestBody :: APIAuthenticationMethod -- | Provides in request query parameter AuthInRequestQuery :: APIAuthenticationMethod instance GHC.Classes.Ord Network.OAuth.OAuth2.HttpClient.APIAuthenticationMethod instance GHC.Classes.Eq Network.OAuth.OAuth2.HttpClient.APIAuthenticationMethod -- | Bindings Authorization part of The OAuth 2.0 Authorization Framework -- RFC6749 https://www.rfc-editor.org/rfc/rfc6749 module Network.OAuth.OAuth2.AuthorizationRequest -- | Authorization Code Grant Error Responses -- https://tools.ietf.org/html/rfc6749#section-4.1.2.1 -- -- I found hard time to figure a way to test the authorization error flow -- When anything wrong in /authorize request, it will stuck at -- the Provider page hence no way for this library to parse error -- response. In other words, /authorize ends up with 4xx or 5xx. -- Revisit this whenever find a case OAuth2 provider redirects back to -- Relying party with errors. data AuthorizationResponseError AuthorizationResponseError :: AuthorizationResponseErrorCode -> Maybe Text -> Maybe (URIRef Absolute) -> AuthorizationResponseError [authorizationResponseError] :: AuthorizationResponseError -> AuthorizationResponseErrorCode [authorizationResponseErrorDescription] :: AuthorizationResponseError -> Maybe Text [authorizationResponseErrorUri] :: AuthorizationResponseError -> Maybe (URIRef Absolute) data AuthorizationResponseErrorCode InvalidRequest :: AuthorizationResponseErrorCode UnauthorizedClient :: AuthorizationResponseErrorCode AccessDenied :: AuthorizationResponseErrorCode UnsupportedResponseType :: AuthorizationResponseErrorCode InvalidScope :: AuthorizationResponseErrorCode ServerError :: AuthorizationResponseErrorCode TemporarilyUnavailable :: AuthorizationResponseErrorCode UnknownErrorCode :: Text -> AuthorizationResponseErrorCode -- | See authorizationUrlWithParams authorizationUrl :: OAuth2 -> URI -- | Prepare the authorization URL. Redirect to this URL asking for user -- interactive authentication. authorizationUrlWithParams :: QueryParams -> OAuth2 -> URI instance GHC.Classes.Eq Network.OAuth.OAuth2.AuthorizationRequest.AuthorizationResponseErrorCode instance GHC.Show.Show Network.OAuth.OAuth2.AuthorizationRequest.AuthorizationResponseErrorCode instance GHC.Classes.Eq Network.OAuth.OAuth2.AuthorizationRequest.AuthorizationResponseError instance GHC.Show.Show Network.OAuth.OAuth2.AuthorizationRequest.AuthorizationResponseError instance Data.Aeson.Types.FromJSON.FromJSON Network.OAuth.OAuth2.AuthorizationRequest.AuthorizationResponseError instance Data.Aeson.Types.FromJSON.FromJSON Network.OAuth.OAuth2.AuthorizationRequest.AuthorizationResponseErrorCode -- | A lightweight oauth2 Haskell binding. See Readme for more details module Network.OAuth.OAuth2 -- | Query Parameter Representation data OAuth2 OAuth2 :: Text -> Text -> URIRef Absolute -> URIRef Absolute -> URIRef Absolute -> OAuth2 [oauth2ClientId] :: OAuth2 -> Text [oauth2ClientSecret] :: OAuth2 -> Text [oauth2AuthorizeEndpoint] :: OAuth2 -> URIRef Absolute [oauth2TokenEndpoint] :: OAuth2 -> URIRef Absolute [oauth2RedirectUri] :: OAuth2 -> URIRef Absolute newtype AccessToken AccessToken :: Text -> AccessToken [atoken] :: AccessToken -> Text newtype RefreshToken RefreshToken :: Text -> RefreshToken [rtoken] :: RefreshToken -> Text newtype IdToken IdToken :: Text -> IdToken [idtoken] :: IdToken -> Text -- | Authorization Code newtype ExchangeToken ExchangeToken :: Text -> ExchangeToken [extoken] :: ExchangeToken -> Text -- | https://www.rfc-editor.org/rfc/rfc6749#section-4.1.4 data OAuth2Token OAuth2Token :: AccessToken -> Maybe RefreshToken -> Maybe Int -> Maybe Text -> Maybe IdToken -> OAuth2Token [accessToken] :: OAuth2Token -> AccessToken -- | Exists when offline_access scope is in the Authorization -- Request and the provider supports Refresh Access Token. [refreshToken] :: OAuth2Token -> Maybe RefreshToken [expiresIn] :: OAuth2Token -> Maybe Int -- | See https://www.rfc-editor.org/rfc/rfc6749#section-5.1. It's -- required per spec. But OAuth2 provider implementation are vary. Maybe -- will remove Maybe in future release. [tokenType] :: OAuth2Token -> Maybe Text -- | Exists when openid scope is in the Authorization Request and -- the provider supports OpenID protocol. [idToken] :: OAuth2Token -> Maybe IdToken -- | https://www.rfc-editor.org/rfc/rfc6749#section-2.3 According to -- spec: -- -- The client MUST NOT use more than one authentication method in each -- request. -- -- Which means use Authorization header or Post body. -- -- However, I found I have to include authentication in the header all -- the time in real world. -- -- In other words, ClientSecretBasic is always assured. -- ClientSecretPost is optional. -- -- Maybe consider an alternative implementation that boolean kind of data -- type is good enough. data ClientAuthenticationMethod ClientSecretBasic :: ClientAuthenticationMethod ClientSecretPost :: ClientAuthenticationMethod ClientAssertionJwt :: ClientAuthenticationMethod -- | Type synonym of post body content type PostBody = [(ByteString, ByteString)] -- | Type sysnonym of request query params type QueryParams = [(ByteString, ByteString)] defaultRequestHeaders :: [(HeaderName, ByteString)] appendQueryParams :: [(ByteString, ByteString)] -> URIRef a -> URIRef a uriToRequest :: MonadThrow m => URI -> m Request requestToUri :: Request -> URI hostLens :: Lens' Request ByteString portLens :: Lens' Request Int -- | See authorizationUrlWithParams authorizationUrl :: OAuth2 -> URI -- | Prepare the authorization URL. Redirect to this URL asking for user -- interactive authentication. authorizationUrlWithParams :: QueryParams -> OAuth2 -> URI module Network.OAuth2.Experiment.Types -- | Idp i consists various endpoints endpoints. -- -- The i is actually phantom type for information only (Idp -- name) at this moment. And it is PolyKinds. -- -- Hence whenever Idp i or IdpApplication i a is used -- as function parameter, PolyKinds need to be enabled. data Idp (i :: k) Idp :: URI -> URI -> URI -> Maybe URI -> Idp (i :: k) -- | Userinfo Endpoint [idpUserInfoEndpoint] :: Idp (i :: k) -> URI -- | Authorization Endpoint [idpAuthorizeEndpoint] :: Idp (i :: k) -> URI -- | Token Endpoint [idpTokenEndpoint] :: Idp (i :: k) -> URI -- | Apparently not all IdP support device code flow [idpDeviceAuthorizationEndpoint] :: Idp (i :: k) -> Maybe URI -- | An OAuth2 Application "a" of IdP "i". "a" can be one of following -- type: -- -- data IdpApplication (i :: k) a IdpApplication :: Idp i -> a -> IdpApplication (i :: k) a [idp] :: IdpApplication (i :: k) a -> Idp i [application] :: IdpApplication (i :: k) a -> a newtype Scope Scope :: Text -> Scope [unScope] :: Scope -> Text -- | Grant type query parameter has association with different GrantType -- flows but not completely strict. -- -- e.g. Both AuthorizationCode and ResourceOwnerPassword flow could -- support refresh token flow. data GrantTypeValue GTAuthorizationCode :: GrantTypeValue GTPassword :: GrantTypeValue GTClientCredentials :: GrantTypeValue GTRefreshToken :: GrantTypeValue GTJwtBearer :: GrantTypeValue GTDeviceCode :: GrantTypeValue data ResponseType Code :: ResponseType newtype ClientId ClientId :: Text -> ClientId [unClientId] :: ClientId -> Text -- | Can be either "Client Secret" or JWT base on client authentication -- method newtype ClientSecret ClientSecret :: Text -> ClientSecret [unClientSecret] :: ClientSecret -> Text -- | In order to reuse some methods from legacy -- Network.OAuth.OAuth2. Will be removed when Experiment module -- becomes default. toOAuth2Key :: ClientId -> ClientSecret -> OAuth2 newtype RedirectUri RedirectUri :: URI -> RedirectUri [unRedirectUri] :: RedirectUri -> URI newtype AuthorizeState AuthorizeState :: Text -> AuthorizeState [unAuthorizeState] :: AuthorizeState -> Text newtype Username Username :: Text -> Username [unUsername] :: Username -> Text newtype Password Password :: Text -> Password [unPassword] :: Password -> Text class ToQueryParam a toQueryParam :: ToQueryParam a => a -> Map Text Text class HasOAuth2Key a mkOAuth2Key :: HasOAuth2Key a => a -> OAuth2 instance GHC.Classes.Ord Network.OAuth2.Experiment.Types.Scope instance GHC.Classes.Eq Network.OAuth2.Experiment.Types.Scope instance GHC.Show.Show Network.OAuth2.Experiment.Types.GrantTypeValue instance GHC.Classes.Eq Network.OAuth2.Experiment.Types.GrantTypeValue instance Data.String.IsString Network.OAuth2.Experiment.Types.ClientId instance GHC.Classes.Eq Network.OAuth2.Experiment.Types.ClientId instance GHC.Show.Show Network.OAuth2.Experiment.Types.ClientId instance Data.String.IsString Network.OAuth2.Experiment.Types.ClientSecret instance GHC.Classes.Eq Network.OAuth2.Experiment.Types.ClientSecret instance GHC.Classes.Eq Network.OAuth2.Experiment.Types.RedirectUri instance GHC.Classes.Eq Network.OAuth2.Experiment.Types.AuthorizeState instance GHC.Classes.Eq Network.OAuth2.Experiment.Types.Username instance GHC.Classes.Eq Network.OAuth2.Experiment.Types.Password instance Network.OAuth2.Experiment.Types.ToQueryParam a => Network.OAuth2.Experiment.Types.ToQueryParam (GHC.Maybe.Maybe a) instance Network.OAuth2.Experiment.Types.ToQueryParam Network.OAuth2.Experiment.Types.GrantTypeValue instance Network.OAuth2.Experiment.Types.ToQueryParam Network.OAuth2.Experiment.Types.ClientId instance Network.OAuth2.Experiment.Types.ToQueryParam Network.OAuth2.Experiment.Types.ClientSecret instance Network.OAuth2.Experiment.Types.ToQueryParam Network.OAuth2.Experiment.Types.Username instance Network.OAuth2.Experiment.Types.ToQueryParam Network.OAuth2.Experiment.Types.Password instance Network.OAuth2.Experiment.Types.ToQueryParam Network.OAuth2.Experiment.Types.AuthorizeState instance Network.OAuth2.Experiment.Types.ToQueryParam Network.OAuth2.Experiment.Types.RedirectUri instance Network.OAuth2.Experiment.Types.ToQueryParam (Data.Set.Internal.Set Network.OAuth2.Experiment.Types.Scope) instance Network.OAuth2.Experiment.Types.ToQueryParam Network.OAuth2.Experiment.Pkce.CodeVerifier instance Network.OAuth2.Experiment.Types.ToQueryParam Network.OAuth2.Experiment.Pkce.CodeChallenge instance Network.OAuth2.Experiment.Types.ToQueryParam Network.OAuth2.Experiment.Pkce.CodeChallengeMethod instance Network.OAuth2.Experiment.Types.ToQueryParam Network.OAuth.OAuth2.Internal.ExchangeToken instance Network.OAuth2.Experiment.Types.ToQueryParam Network.OAuth.OAuth2.Internal.RefreshToken instance Network.OAuth2.Experiment.Types.ToQueryParam Network.OAuth2.Experiment.Types.ResponseType instance Data.String.IsString Network.OAuth2.Experiment.Types.Password instance Data.String.IsString Network.OAuth2.Experiment.Types.Username instance Data.String.IsString Network.OAuth2.Experiment.Types.AuthorizeState instance Data.String.IsString Network.OAuth2.Experiment.Types.Scope module Network.OAuth2.Experiment.Flows.UserInfoRequest class HasUserInfoRequest a -- | Standard approach of fetching /userinfo conduitUserInfoRequest :: (MonadIO m, HasUserInfoRequest a, FromJSON b) => IdpApplication i a -> Manager -> AccessToken -> ExceptT ByteString m b -- | Usually conduitUserInfoRequest is good enough. But some IdP has -- different approach to fetch user information rather than GET. This -- method gives the flexiblity. conduitUserInfoRequestWithCustomMethod :: (MonadIO m, HasUserInfoRequest a, FromJSON b) => (Manager -> AccessToken -> URI -> ExceptT ByteString m b) -> IdpApplication i a -> Manager -> AccessToken -> ExceptT ByteString m b module Network.OAuth2.Experiment.Flows.TokenRequest class HasTokenRequestClientAuthenticationMethod a getClientAuthenticationMethod :: HasTokenRequestClientAuthenticationMethod a => a -> ClientAuthenticationMethod -- | Only Authorization Code Grant involves a Exchange Token (Authorization -- Code). ResourceOwnerPassword and Client Credentials make token request -- directly. data NoNeedExchangeToken NoNeedExchangeToken :: NoNeedExchangeToken class (HasOAuth2Key a, HasTokenRequestClientAuthenticationMethod a) => HasTokenRequest a where { data TokenRequest a; type ExchangeTokenInfo a; } -- | Only 'AuthorizationCode flow (but not resource owner password nor -- client credentials) will use ExchangeToken in the token request -- create type family to be explicit on it. with 'type instance -- WithExchangeToken a b = b' implies no exchange token v.s. 'type -- instance WithExchangeToken a b = ExchangeToken -> b' implies -- needing an exchange token type WithExchangeToken a b mkTokenRequestParam :: HasTokenRequest a => a -> ExchangeTokenInfo a -> TokenRequest a -- | Make Token Request -- https://www.rfc-editor.org/rfc/rfc6749#section-4.1.3 conduitTokenRequest :: (HasTokenRequest a, ToQueryParam (TokenRequest a), MonadIO m) => IdpApplication i a -> Manager -> ExchangeTokenInfo a -> ExceptT TokenResponseError m OAuth2Token -- | Make Token Request (PKCE) -- https://datatracker.ietf.org/doc/html/rfc7636#section-4.5 conduitPkceTokenRequest :: (HasTokenRequest a, ToQueryParam (TokenRequest a), MonadIO m) => IdpApplication i a -> Manager -> (ExchangeTokenInfo a, CodeVerifier) -> ExceptT TokenResponseError m OAuth2Token module Network.OAuth2.Experiment.Grants.JwtBearer -- | An Application that supports "JWT Bearer" flow -- -- https://datatracker.ietf.org/doc/html/rfc7523 data JwtBearerApplication JwtBearerApplication :: Text -> ByteString -> JwtBearerApplication [jbName] :: JwtBearerApplication -> Text [jbJwtAssertion] :: JwtBearerApplication -> ByteString instance Network.OAuth2.Experiment.Types.HasOAuth2Key Network.OAuth2.Experiment.Grants.JwtBearer.JwtBearerApplication instance Network.OAuth2.Experiment.Flows.TokenRequest.HasTokenRequestClientAuthenticationMethod Network.OAuth2.Experiment.Grants.JwtBearer.JwtBearerApplication instance Network.OAuth2.Experiment.Flows.TokenRequest.HasTokenRequest Network.OAuth2.Experiment.Grants.JwtBearer.JwtBearerApplication instance Network.OAuth2.Experiment.Types.ToQueryParam (Network.OAuth2.Experiment.Flows.TokenRequest.TokenRequest Network.OAuth2.Experiment.Grants.JwtBearer.JwtBearerApplication) instance Network.OAuth2.Experiment.Flows.UserInfoRequest.HasUserInfoRequest Network.OAuth2.Experiment.Grants.JwtBearer.JwtBearerApplication module Network.OAuth2.Experiment.Grants.ClientCredentials -- | An Application that supports "Client Credentials" flow -- -- https://www.rfc-editor.org/rfc/rfc6749#section-4.4 data ClientCredentialsApplication ClientCredentialsApplication :: ClientId -> ClientSecret -> Text -> Set Scope -> Map Text Text -> ClientAuthenticationMethod -> ClientCredentialsApplication [ccClientId] :: ClientCredentialsApplication -> ClientId [ccClientSecret] :: ClientCredentialsApplication -> ClientSecret [ccName] :: ClientCredentialsApplication -> Text [ccScope] :: ClientCredentialsApplication -> Set Scope [ccTokenRequestExtraParams] :: ClientCredentialsApplication -> Map Text Text [ccTokenRequestAuthenticationMethod] :: ClientCredentialsApplication -> ClientAuthenticationMethod instance Network.OAuth2.Experiment.Types.HasOAuth2Key Network.OAuth2.Experiment.Grants.ClientCredentials.ClientCredentialsApplication instance Network.OAuth2.Experiment.Flows.TokenRequest.HasTokenRequestClientAuthenticationMethod Network.OAuth2.Experiment.Grants.ClientCredentials.ClientCredentialsApplication instance Network.OAuth2.Experiment.Flows.TokenRequest.HasTokenRequest Network.OAuth2.Experiment.Grants.ClientCredentials.ClientCredentialsApplication instance Network.OAuth2.Experiment.Types.ToQueryParam (Network.OAuth2.Experiment.Flows.TokenRequest.TokenRequest Network.OAuth2.Experiment.Grants.ClientCredentials.ClientCredentialsApplication) module Network.OAuth2.Experiment.Flows.RefreshTokenRequest data RefreshTokenRequest RefreshTokenRequest :: RefreshToken -> GrantTypeValue -> Set Scope -> RefreshTokenRequest [rrRefreshToken] :: RefreshTokenRequest -> RefreshToken [rrGrantType] :: RefreshTokenRequest -> GrantTypeValue [rrScope] :: RefreshTokenRequest -> Set Scope class (HasOAuth2Key a, HasTokenRequestClientAuthenticationMethod a) => HasRefreshTokenRequest a -- | Make Refresh Token Request parameters | -- https://www.rfc-editor.org/rfc/rfc6749#section-6 mkRefreshTokenRequestParam :: HasRefreshTokenRequest a => a -> RefreshToken -> RefreshTokenRequest -- | Make Refresh Token Request -- https://www.rfc-editor.org/rfc/rfc6749#section-6 conduitRefreshTokenRequest :: (MonadIO m, HasRefreshTokenRequest a) => IdpApplication i a -> Manager -> RefreshToken -> ExceptT TokenResponseError m OAuth2Token instance Network.OAuth2.Experiment.Types.ToQueryParam Network.OAuth2.Experiment.Flows.RefreshTokenRequest.RefreshTokenRequest module Network.OAuth2.Experiment.Grants.ResourceOwnerPassword -- | An Application that supports "Resource Owner Password" flow -- -- https://www.rfc-editor.org/rfc/rfc6749#section-4.3 data ResourceOwnerPasswordApplication ResourceOwnerPasswordApplication :: ClientId -> ClientSecret -> Text -> Set Scope -> Username -> Password -> Map Text Text -> ResourceOwnerPasswordApplication [ropClientId] :: ResourceOwnerPasswordApplication -> ClientId [ropClientSecret] :: ResourceOwnerPasswordApplication -> ClientSecret [ropName] :: ResourceOwnerPasswordApplication -> Text [ropScope] :: ResourceOwnerPasswordApplication -> Set Scope [ropUserName] :: ResourceOwnerPasswordApplication -> Username [ropPassword] :: ResourceOwnerPasswordApplication -> Password [ropTokenRequestExtraParams] :: ResourceOwnerPasswordApplication -> Map Text Text instance Network.OAuth2.Experiment.Types.HasOAuth2Key Network.OAuth2.Experiment.Grants.ResourceOwnerPassword.ResourceOwnerPasswordApplication instance Network.OAuth2.Experiment.Flows.TokenRequest.HasTokenRequestClientAuthenticationMethod Network.OAuth2.Experiment.Grants.ResourceOwnerPassword.ResourceOwnerPasswordApplication instance Network.OAuth2.Experiment.Flows.TokenRequest.HasTokenRequest Network.OAuth2.Experiment.Grants.ResourceOwnerPassword.ResourceOwnerPasswordApplication instance Network.OAuth2.Experiment.Types.ToQueryParam (Network.OAuth2.Experiment.Flows.TokenRequest.TokenRequest Network.OAuth2.Experiment.Grants.ResourceOwnerPassword.ResourceOwnerPasswordApplication) instance Network.OAuth2.Experiment.Flows.UserInfoRequest.HasUserInfoRequest Network.OAuth2.Experiment.Grants.ResourceOwnerPassword.ResourceOwnerPasswordApplication instance Network.OAuth2.Experiment.Flows.RefreshTokenRequest.HasRefreshTokenRequest Network.OAuth2.Experiment.Grants.ResourceOwnerPassword.ResourceOwnerPasswordApplication module Network.OAuth2.Experiment.Flows.DeviceAuthorizationRequest newtype DeviceCode DeviceCode :: Text -> DeviceCode -- | https://www.rfc-editor.org/rfc/rfc8628#section-3.2 data DeviceAuthorizationResponse DeviceAuthorizationResponse :: DeviceCode -> Text -> URI -> Maybe URI -> Integer -> Maybe Int -> DeviceAuthorizationResponse [deviceCode] :: DeviceAuthorizationResponse -> DeviceCode [userCode] :: DeviceAuthorizationResponse -> Text [verificationUri] :: DeviceAuthorizationResponse -> URI [verificationUriComplete] :: DeviceAuthorizationResponse -> Maybe URI [expiresIn] :: DeviceAuthorizationResponse -> Integer [interval] :: DeviceAuthorizationResponse -> Maybe Int data DeviceAuthorizationRequestParam DeviceAuthorizationRequestParam :: Set Scope -> Maybe ClientId -> Map Text Text -> DeviceAuthorizationRequestParam [arScope] :: DeviceAuthorizationRequestParam -> Set Scope [arClientId] :: DeviceAuthorizationRequestParam -> Maybe ClientId [arExtraParams] :: DeviceAuthorizationRequestParam -> Map Text Text class HasOAuth2Key a => HasDeviceAuthorizationRequest a -- | Create Device Authorization Request parameters -- https://www.rfc-editor.org/rfc/rfc8628#section-3.1 mkDeviceAuthorizationRequestParam :: HasDeviceAuthorizationRequest a => a -> DeviceAuthorizationRequestParam -- | Makes Device Authorization Request -- https://www.rfc-editor.org/rfc/rfc8628#section-3.1 conduitDeviceAuthorizationRequest :: (MonadIO m, HasDeviceAuthorizationRequest a) => IdpApplication i a -> Manager -> ExceptT ByteString m DeviceAuthorizationResponse instance Data.Aeson.Types.FromJSON.FromJSON Network.OAuth2.Experiment.Flows.DeviceAuthorizationRequest.DeviceCode instance Network.OAuth2.Experiment.Types.ToQueryParam Network.OAuth2.Experiment.Flows.DeviceAuthorizationRequest.DeviceAuthorizationRequestParam instance Data.Aeson.Types.FromJSON.FromJSON Network.OAuth2.Experiment.Flows.DeviceAuthorizationRequest.DeviceAuthorizationResponse instance Network.OAuth2.Experiment.Types.ToQueryParam Network.OAuth2.Experiment.Flows.DeviceAuthorizationRequest.DeviceCode module Network.OAuth2.Experiment.Grants.DeviceAuthorization -- | An Application that supports "Device Authorization Grant" -- -- https://www.rfc-editor.org/rfc/rfc8628#section-3.1 data DeviceAuthorizationApplication DeviceAuthorizationApplication :: Text -> ClientId -> ClientSecret -> Set Scope -> Map Text Text -> Maybe ClientAuthenticationMethod -> DeviceAuthorizationApplication [daName] :: DeviceAuthorizationApplication -> Text [daClientId] :: DeviceAuthorizationApplication -> ClientId [daClientSecret] :: DeviceAuthorizationApplication -> ClientSecret [daScope] :: DeviceAuthorizationApplication -> Set Scope -- | Additional parameters to the device authorization request. Most of -- identity providers follow the spec strictly but AzureAD requires -- "tenant" parameter. [daAuthorizationRequestExtraParam] :: DeviceAuthorizationApplication -> Map Text Text -- | The spec requires similar authentication method as /token request. -- Most of identity providers doesn't required it but some does like -- Okta. [daAuthorizationRequestAuthenticationMethod] :: DeviceAuthorizationApplication -> Maybe ClientAuthenticationMethod pollDeviceTokenRequest :: MonadIO m => IdpApplication i DeviceAuthorizationApplication -> Manager -> DeviceAuthorizationResponse -> ExceptT TokenResponseError m OAuth2Token instance Network.OAuth2.Experiment.Types.HasOAuth2Key Network.OAuth2.Experiment.Grants.DeviceAuthorization.DeviceAuthorizationApplication instance Network.OAuth2.Experiment.Flows.TokenRequest.HasTokenRequestClientAuthenticationMethod Network.OAuth2.Experiment.Grants.DeviceAuthorization.DeviceAuthorizationApplication instance Network.OAuth2.Experiment.Flows.DeviceAuthorizationRequest.HasDeviceAuthorizationRequest Network.OAuth2.Experiment.Grants.DeviceAuthorization.DeviceAuthorizationApplication instance Network.OAuth2.Experiment.Flows.TokenRequest.HasTokenRequest Network.OAuth2.Experiment.Grants.DeviceAuthorization.DeviceAuthorizationApplication instance Network.OAuth2.Experiment.Types.ToQueryParam (Network.OAuth2.Experiment.Flows.TokenRequest.TokenRequest Network.OAuth2.Experiment.Grants.DeviceAuthorization.DeviceAuthorizationApplication) instance Network.OAuth2.Experiment.Flows.UserInfoRequest.HasUserInfoRequest Network.OAuth2.Experiment.Grants.DeviceAuthorization.DeviceAuthorizationApplication module Network.OAuth2.Experiment.Flows.AuthorizationRequest data AuthorizationRequestParam AuthorizationRequestParam :: Set Scope -> AuthorizeState -> ClientId -> Maybe RedirectUri -> ResponseType -> Map Text Text -> AuthorizationRequestParam [arScope] :: AuthorizationRequestParam -> Set Scope [arState] :: AuthorizationRequestParam -> AuthorizeState [arClientId] :: AuthorizationRequestParam -> ClientId [arRedirectUri] :: AuthorizationRequestParam -> Maybe RedirectUri -- | It could be optional there is only one redirect_uri registered. See: -- https://www.rfc-editor.org/rfc/rfc6749#section-3.1.2.3 [arResponseType] :: AuthorizationRequestParam -> ResponseType [arExtraParams] :: AuthorizationRequestParam -> Map Text Text class HasAuthorizeRequest a -- | Constructs Authorization Code request parameters | -- https://www.rfc-editor.org/rfc/rfc6749#section-4.1.1 mkAuthorizationRequestParam :: HasAuthorizeRequest a => a -> AuthorizationRequestParam -- | Constructs Authorization Code request URI -- https://www.rfc-editor.org/rfc/rfc6749#section-4.1.1 mkAuthorizationRequest :: HasAuthorizeRequest a => IdpApplication i a -> URI -- | https://datatracker.ietf.org/doc/html/rfc7636 class HasAuthorizeRequest a => HasPkceAuthorizeRequest a mkPkceAuthorizeRequestParam :: (HasPkceAuthorizeRequest a, MonadIO m) => a -> m (AuthorizationRequestParam, CodeVerifier) -- | Constructs Authorization Code (PKCE) request URI and the Code -- Verifier. https://datatracker.ietf.org/doc/html/rfc7636 mkPkceAuthorizeRequest :: (MonadIO m, HasPkceAuthorizeRequest a) => IdpApplication i a -> m (URI, CodeVerifier) instance Network.OAuth2.Experiment.Types.ToQueryParam Network.OAuth2.Experiment.Flows.AuthorizationRequest.AuthorizationRequestParam module Network.OAuth2.Experiment.Grants.AuthorizationCode -- | An Application that supports "Authorization code" flow -- -- https://www.rfc-editor.org/rfc/rfc6749#section-4.1 data AuthorizationCodeApplication AuthorizationCodeApplication :: Text -> ClientId -> ClientSecret -> Set Scope -> URI -> AuthorizeState -> Map Text Text -> ClientAuthenticationMethod -> AuthorizationCodeApplication [acName] :: AuthorizationCodeApplication -> Text [acClientId] :: AuthorizationCodeApplication -> ClientId [acClientSecret] :: AuthorizationCodeApplication -> ClientSecret [acScope] :: AuthorizationCodeApplication -> Set Scope [acRedirectUri] :: AuthorizationCodeApplication -> URI [acAuthorizeState] :: AuthorizationCodeApplication -> AuthorizeState [acAuthorizeRequestExtraParams] :: AuthorizationCodeApplication -> Map Text Text [acTokenRequestAuthenticationMethod] :: AuthorizationCodeApplication -> ClientAuthenticationMethod instance Network.OAuth2.Experiment.Types.HasOAuth2Key Network.OAuth2.Experiment.Grants.AuthorizationCode.AuthorizationCodeApplication instance Network.OAuth2.Experiment.Flows.TokenRequest.HasTokenRequestClientAuthenticationMethod Network.OAuth2.Experiment.Grants.AuthorizationCode.AuthorizationCodeApplication instance Network.OAuth2.Experiment.Flows.AuthorizationRequest.HasAuthorizeRequest Network.OAuth2.Experiment.Grants.AuthorizationCode.AuthorizationCodeApplication instance Network.OAuth2.Experiment.Flows.AuthorizationRequest.HasPkceAuthorizeRequest Network.OAuth2.Experiment.Grants.AuthorizationCode.AuthorizationCodeApplication instance Network.OAuth2.Experiment.Flows.TokenRequest.HasTokenRequest Network.OAuth2.Experiment.Grants.AuthorizationCode.AuthorizationCodeApplication instance Network.OAuth2.Experiment.Types.ToQueryParam (Network.OAuth2.Experiment.Flows.TokenRequest.TokenRequest Network.OAuth2.Experiment.Grants.AuthorizationCode.AuthorizationCodeApplication) instance Network.OAuth2.Experiment.Flows.UserInfoRequest.HasUserInfoRequest Network.OAuth2.Experiment.Grants.AuthorizationCode.AuthorizationCodeApplication instance Network.OAuth2.Experiment.Flows.RefreshTokenRequest.HasRefreshTokenRequest Network.OAuth2.Experiment.Grants.AuthorizationCode.AuthorizationCodeApplication -- | 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. --
  3. Resource Owner Password. This flow only requires to hit token -- endpoint with, of course, username and password, to obtain -- tokens.
  4. --
  5. 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.
  6. --
  7. PKCE (rfc7636). This is enhancement on top of authorization code -- flow.
  8. --
-- -- 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 -- | An Application that supports "Authorization code" flow -- -- https://www.rfc-editor.org/rfc/rfc6749#section-4.1 data AuthorizationCodeApplication AuthorizationCodeApplication :: Text -> ClientId -> ClientSecret -> Set Scope -> URI -> AuthorizeState -> Map Text Text -> ClientAuthenticationMethod -> AuthorizationCodeApplication [acName] :: AuthorizationCodeApplication -> Text [acClientId] :: AuthorizationCodeApplication -> ClientId [acClientSecret] :: AuthorizationCodeApplication -> ClientSecret [acScope] :: AuthorizationCodeApplication -> Set Scope [acRedirectUri] :: AuthorizationCodeApplication -> URI [acAuthorizeState] :: AuthorizationCodeApplication -> AuthorizeState [acAuthorizeRequestExtraParams] :: AuthorizationCodeApplication -> Map Text Text [acTokenRequestAuthenticationMethod] :: AuthorizationCodeApplication -> ClientAuthenticationMethod -- | An Application that supports "Device Authorization Grant" -- -- https://www.rfc-editor.org/rfc/rfc8628#section-3.1 data DeviceAuthorizationApplication DeviceAuthorizationApplication :: Text -> ClientId -> ClientSecret -> Set Scope -> Map Text Text -> Maybe ClientAuthenticationMethod -> DeviceAuthorizationApplication [daName] :: DeviceAuthorizationApplication -> Text [daClientId] :: DeviceAuthorizationApplication -> ClientId [daClientSecret] :: DeviceAuthorizationApplication -> ClientSecret [daScope] :: DeviceAuthorizationApplication -> Set Scope -- | Additional parameters to the device authorization request. Most of -- identity providers follow the spec strictly but AzureAD requires -- "tenant" parameter. [daAuthorizationRequestExtraParam] :: DeviceAuthorizationApplication -> Map Text Text -- | The spec requires similar authentication method as /token request. -- Most of identity providers doesn't required it but some does like -- Okta. [daAuthorizationRequestAuthenticationMethod] :: DeviceAuthorizationApplication -> Maybe ClientAuthenticationMethod pollDeviceTokenRequest :: MonadIO m => IdpApplication i DeviceAuthorizationApplication -> Manager -> DeviceAuthorizationResponse -> ExceptT TokenResponseError m OAuth2Token -- | An Application that supports "Client Credentials" flow -- -- https://www.rfc-editor.org/rfc/rfc6749#section-4.4 data ClientCredentialsApplication ClientCredentialsApplication :: ClientId -> ClientSecret -> Text -> Set Scope -> Map Text Text -> ClientAuthenticationMethod -> ClientCredentialsApplication [ccClientId] :: ClientCredentialsApplication -> ClientId [ccClientSecret] :: ClientCredentialsApplication -> ClientSecret [ccName] :: ClientCredentialsApplication -> Text [ccScope] :: ClientCredentialsApplication -> Set Scope [ccTokenRequestExtraParams] :: ClientCredentialsApplication -> Map Text Text [ccTokenRequestAuthenticationMethod] :: ClientCredentialsApplication -> ClientAuthenticationMethod -- | An Application that supports "Resource Owner Password" flow -- -- https://www.rfc-editor.org/rfc/rfc6749#section-4.3 data ResourceOwnerPasswordApplication ResourceOwnerPasswordApplication :: ClientId -> ClientSecret -> Text -> Set Scope -> Username -> Password -> Map Text Text -> ResourceOwnerPasswordApplication [ropClientId] :: ResourceOwnerPasswordApplication -> ClientId [ropClientSecret] :: ResourceOwnerPasswordApplication -> ClientSecret [ropName] :: ResourceOwnerPasswordApplication -> Text [ropScope] :: ResourceOwnerPasswordApplication -> Set Scope [ropUserName] :: ResourceOwnerPasswordApplication -> Username [ropPassword] :: ResourceOwnerPasswordApplication -> Password [ropTokenRequestExtraParams] :: ResourceOwnerPasswordApplication -> Map Text Text -- | An Application that supports "JWT Bearer" flow -- -- https://datatracker.ietf.org/doc/html/rfc7523 data JwtBearerApplication JwtBearerApplication :: Text -> ByteString -> JwtBearerApplication [jbName] :: JwtBearerApplication -> Text [jbJwtAssertion] :: JwtBearerApplication -> ByteString class HasAuthorizeRequest a -- | Constructs Authorization Code request URI -- https://www.rfc-editor.org/rfc/rfc6749#section-4.1.1 mkAuthorizationRequest :: HasAuthorizeRequest a => IdpApplication i a -> URI -- | Constructs Authorization Code (PKCE) request URI and the Code -- Verifier. https://datatracker.ietf.org/doc/html/rfc7636 mkPkceAuthorizeRequest :: (MonadIO m, HasPkceAuthorizeRequest a) => IdpApplication i a -> m (URI, CodeVerifier) -- | https://www.rfc-editor.org/rfc/rfc8628#section-3.2 data DeviceAuthorizationResponse DeviceAuthorizationResponse :: DeviceCode -> Text -> URI -> Maybe URI -> Integer -> Maybe Int -> DeviceAuthorizationResponse [deviceCode] :: DeviceAuthorizationResponse -> DeviceCode [userCode] :: DeviceAuthorizationResponse -> Text [verificationUri] :: DeviceAuthorizationResponse -> URI [verificationUriComplete] :: DeviceAuthorizationResponse -> Maybe URI [expiresIn] :: DeviceAuthorizationResponse -> Integer [interval] :: DeviceAuthorizationResponse -> Maybe Int class HasOAuth2Key a => HasDeviceAuthorizationRequest a -- | Makes Device Authorization Request -- https://www.rfc-editor.org/rfc/rfc8628#section-3.1 conduitDeviceAuthorizationRequest :: (MonadIO m, HasDeviceAuthorizationRequest a) => IdpApplication i a -> Manager -> ExceptT ByteString m DeviceAuthorizationResponse class (HasOAuth2Key a, HasTokenRequestClientAuthenticationMethod a) => HasTokenRequest a where { data TokenRequest a; type ExchangeTokenInfo a; } -- | Only Authorization Code Grant involves a Exchange Token (Authorization -- Code). ResourceOwnerPassword and Client Credentials make token request -- directly. data NoNeedExchangeToken NoNeedExchangeToken :: NoNeedExchangeToken -- | Make Token Request (PKCE) -- https://datatracker.ietf.org/doc/html/rfc7636#section-4.5 conduitPkceTokenRequest :: (HasTokenRequest a, ToQueryParam (TokenRequest a), MonadIO m) => IdpApplication i a -> Manager -> (ExchangeTokenInfo a, CodeVerifier) -> ExceptT TokenResponseError m OAuth2Token -- | Make Token Request -- https://www.rfc-editor.org/rfc/rfc6749#section-4.1.3 conduitTokenRequest :: (HasTokenRequest a, ToQueryParam (TokenRequest a), MonadIO m) => IdpApplication i a -> Manager -> ExchangeTokenInfo a -> ExceptT TokenResponseError m OAuth2Token class (HasOAuth2Key a, HasTokenRequestClientAuthenticationMethod a) => HasRefreshTokenRequest a -- | Make Refresh Token Request -- https://www.rfc-editor.org/rfc/rfc6749#section-6 conduitRefreshTokenRequest :: (MonadIO m, HasRefreshTokenRequest a) => IdpApplication i a -> Manager -> RefreshToken -> ExceptT TokenResponseError m OAuth2Token class HasUserInfoRequest a -- | Standard approach of fetching /userinfo conduitUserInfoRequest :: (MonadIO m, HasUserInfoRequest a, FromJSON b) => IdpApplication i a -> Manager -> AccessToken -> ExceptT ByteString m b -- | Usually conduitUserInfoRequest is good enough. But some IdP has -- different approach to fetch user information rather than GET. This -- method gives the flexiblity. conduitUserInfoRequestWithCustomMethod :: (MonadIO m, HasUserInfoRequest a, FromJSON b) => (Manager -> AccessToken -> URI -> ExceptT ByteString m b) -> IdpApplication i a -> Manager -> AccessToken -> ExceptT ByteString m b newtype AuthorizeState AuthorizeState :: Text -> AuthorizeState [unAuthorizeState] :: AuthorizeState -> Text newtype ClientId ClientId :: Text -> ClientId [unClientId] :: ClientId -> Text -- | Can be either "Client Secret" or JWT base on client authentication -- method newtype ClientSecret ClientSecret :: Text -> ClientSecret [unClientSecret] :: ClientSecret -> Text class HasOAuth2Key a -- | Idp i consists various endpoints endpoints. -- -- The i is actually phantom type for information only (Idp -- name) at this moment. And it is PolyKinds. -- -- Hence whenever Idp i or IdpApplication i a is used -- as function parameter, PolyKinds need to be enabled. data Idp (i :: k) Idp :: URI -> URI -> URI -> Maybe URI -> Idp (i :: k) -- | Userinfo Endpoint [idpUserInfoEndpoint] :: Idp (i :: k) -> URI -- | Authorization Endpoint [idpAuthorizeEndpoint] :: Idp (i :: k) -> URI -- | Token Endpoint [idpTokenEndpoint] :: Idp (i :: k) -> URI -- | Apparently not all IdP support device code flow [idpDeviceAuthorizationEndpoint] :: Idp (i :: k) -> Maybe URI -- | An OAuth2 Application "a" of IdP "i". "a" can be one of following -- type: -- -- data IdpApplication (i :: k) a IdpApplication :: Idp i -> a -> IdpApplication (i :: k) a [idp] :: IdpApplication (i :: k) a -> Idp i [application] :: IdpApplication (i :: k) a -> a newtype Password Password :: Text -> Password [unPassword] :: Password -> Text newtype RedirectUri RedirectUri :: URI -> RedirectUri [unRedirectUri] :: RedirectUri -> URI newtype Scope Scope :: Text -> Scope [unScope] :: Scope -> Text newtype Username Username :: Text -> Username [unUsername] :: Username -> Text newtype CodeVerifier CodeVerifier :: Text -> CodeVerifier [unCodeVerifier] :: CodeVerifier -> Text -- | https://www.rfc-editor.org/rfc/rfc6749#section-2.3 According to -- spec: -- -- The client MUST NOT use more than one authentication method in each -- request. -- -- Which means use Authorization header or Post body. -- -- However, I found I have to include authentication in the header all -- the time in real world. -- -- In other words, ClientSecretBasic is always assured. -- ClientSecretPost is optional. -- -- Maybe consider an alternative implementation that boolean kind of data -- type is good enough. data ClientAuthenticationMethod ClientSecretBasic :: ClientAuthenticationMethod ClientSecretPost :: ClientAuthenticationMethod ClientAssertionJwt :: ClientAuthenticationMethod uriToText :: URI -> Text