-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Haskell OAuth2 authentication client -- -- Haskell OAuth2 authentication client. -- -- Tutorial -- https://github.com/freizl/hoauth2/tree/main/hoauth2-tutorial/ -- -- Demo application -- https://github.com/freizl/hoauth2-demo/tree/main/hoauth2-demo/ @package hoauth2 @version 2.7.0 -- | 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 TokenRequestError TokenRequestError :: TokenRequestErrorCode -> Maybe Text -> Maybe (URIRef Absolute) -> TokenRequestError [error] :: TokenRequestError -> TokenRequestErrorCode [errorDescription] :: TokenRequestError -> Maybe Text [errorUri] :: TokenRequestError -> Maybe (URIRef Absolute) -- | Token Error Responses -- https://tools.ietf.org/html/rfc6749#section-5.2 data TokenRequestErrorCode InvalidRequest :: TokenRequestErrorCode InvalidClient :: TokenRequestErrorCode InvalidGrant :: TokenRequestErrorCode UnauthorizedClient :: TokenRequestErrorCode UnsupportedGrantType :: TokenRequestErrorCode InvalidScope :: TokenRequestErrorCode UnknownErrorCode :: Text -> TokenRequestErrorCode parseTokeRequestError :: ByteString -> TokenRequestError -- | 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 TokenRequestError m OAuth2Token -- | Deprecated: use fetchAccessTokenWithAuthMethod fetchAccessToken2 :: MonadIO m => Manager -> OAuth2 -> ExchangeToken -> ExceptT TokenRequestError m OAuth2Token -- | Deprecated: use fetchAccessTokenWithAuthMethod fetchAccessTokenInternal :: MonadIO m => ClientAuthenticationMethod -> Manager -> OAuth2 -> ExchangeToken -> ExceptT TokenRequestError 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 TokenRequestError m OAuth2Token -- | Fetch a new AccessToken using the Refresh Token with authentication in -- request header. refreshAccessToken :: MonadIO m => Manager -> OAuth2 -> RefreshToken -> ExceptT TokenRequestError m OAuth2Token -- | Deprecated: use refreshAccessTokenWithAuthMethod refreshAccessToken2 :: MonadIO m => Manager -> OAuth2 -> RefreshToken -> ExceptT TokenRequestError m OAuth2Token -- | Deprecated: use refreshAccessTokenWithAuthMethod refreshAccessTokenInternal :: MonadIO m => ClientAuthenticationMethod -> Manager -> OAuth2 -> RefreshToken -> ExceptT TokenRequestError 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 TokenRequestError m OAuth2Token -- | Conduct post request and return response as JSON. doJSONPostRequest :: (MonadIO m, FromJSON a) => Manager -> OAuth2 -> URI -> PostBody -> ExceptT TokenRequestError m a -- | Conduct post request. doSimplePostRequest :: MonadIO m => Manager -> OAuth2 -> URI -> PostBody -> ExceptT TokenRequestError m ByteString -- | Gets response body from a Response if 200 otherwise assume -- OAuth2Error handleOAuth2TokenResponse :: Response ByteString -> Either TokenRequestError ByteString -- | Try to parses response as JSON, if failed, try to parse as like query -- string. parseResponseFlexible :: FromJSON a => ByteString -> Either TokenRequestError a -- | Parses the response that contains not JSON but a Query String parseResponseString :: FromJSON a => ByteString -> Either TokenRequestError a -- | 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.TokenRequestErrorCode instance GHC.Show.Show Network.OAuth.OAuth2.TokenRequest.TokenRequestErrorCode instance GHC.Generics.Generic Network.OAuth.OAuth2.TokenRequest.TokenRequestError instance GHC.Classes.Eq Network.OAuth.OAuth2.TokenRequest.TokenRequestError instance GHC.Show.Show Network.OAuth.OAuth2.TokenRequest.TokenRequestError instance Data.Aeson.Types.FromJSON.FromJSON Network.OAuth.OAuth2.TokenRequest.TokenRequestError instance Data.Aeson.Types.FromJSON.FromJSON Network.OAuth.OAuth2.TokenRequest.TokenRequestErrorCode -- | 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 :: (FromJSON a, MonadIO m) => 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 authGetJSONInternal :: (FromJSON a, MonadIO m) => 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 :: (FromJSON a, MonadIO m) => 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 :: (FromJSON a, MonadIO m) => APIAuthenticationMethod -> Manager -> AccessToken -> URI -> PostBody -> ExceptT ByteString m a -- | Deprecated: use authPostJSONWithAuthMethod authPostJSONInternal :: (FromJSON a, MonadIO m) => 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 Errors InvalidRequest :: Errors UnauthorizedClient :: Errors AccessDenied :: Errors UnsupportedResponseType :: Errors InvalidScope :: Errors ServerError :: Errors TemporarilyUnavailable :: Errors -- | See authorizationUrlWithParams authorizationUrl :: OAuth2 -> URI -- | Prepare the authorization URL. Redirect to this URL asking for user -- interactive authentication. authorizationUrlWithParams :: QueryParams -> OAuth2 -> URI instance GHC.Generics.Generic Network.OAuth.OAuth2.AuthorizationRequest.Errors instance GHC.Classes.Eq Network.OAuth.OAuth2.AuthorizationRequest.Errors instance GHC.Show.Show Network.OAuth.OAuth2.AuthorizationRequest.Errors instance Data.Aeson.Types.FromJSON.FromJSON Network.OAuth.OAuth2.AuthorizationRequest.Errors -- | A lightweight oauth2 Haskell binding. See Readme for more details module Network.OAuth.OAuth2 -- | See authorizationUrlWithParams authorizationUrl :: OAuth2 -> URI -- | Prepare the authorization URL. Redirect to this URL asking for user -- interactive authentication. authorizationUrlWithParams :: QueryParams -> OAuth2 -> URI -- | 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 -- authorizeUrl 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 authorizeUrl and -- the provider supports OpenID. [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, in reality, I always have to include authentication in the -- header. -- -- In other words, ClientSecrectBasic 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 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 -- | 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. (TBD but likely -- 3.0). -- -- The key concept/change is to introduce the GrantTypeFlow, 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) and more or less obsolete 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. -- --
--   data Google = Google deriving (Eq, Show)
--   googleIdp = Idp Google
--     Idp
--       { idpFetchUserInfo = authGetJSON @(IdpUserInfo Google),
--         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|]
--       }
--   
--   fooApp :: IdpApplication 'AuthorizationCode Google
--   fooApp =
--     AuthorizationCodeIdpApplication
--       { idpAppClientId = "xxxxx",
--         idpAppClientSecret = "xxxxx",
--         idpAppScope =
--           Set.fromList
--             [ "https://www.googleapis.com/auth/userinfo.email",
--               "https://www.googleapis.com/auth/userinfo.profile"
--             ],
--         idpAppAuthorizeState = "CHANGE_ME",
--         idpAppAuthorizeExtraParams = Map.empty,
--         idpAppRedirectUri = [uri|http://localhost/oauth2/callback|],
--         idpAppName = "default-google-App",
--         idpAppTokenRequestAuthenticationMethod = ClientSecretBasic,
--         idp = googleIdp
--       }
--   
-- -- Secondly, construct the authorize URL. -- --
--   authorizeUrl = mkAuthorizeRequest fooApp
--   
-- -- Thirdly, after a successful redirect with authorize code, you could -- exchange for access token -- --
--   mgr <- liftIO $ newManager tlsManagerSettings
--   tokenResp <- conduitTokenRequest fooApp mgr authorizeCode
--   
-- -- Lastly, you probably like to fetch user info -- --
--   conduitUserInfoRequest fooApp mgr (accessToken tokenResp)
--   
-- -- Also you could find example from hoauth2-providers-tutorials -- module. module Network.OAuth2.Experiment data GrantTypeFlow -- | https://www.rfc-editor.org/rfc/rfc6749#section-4.1 AuthorizationCode :: GrantTypeFlow -- | https://www.rfc-editor.org/rfc/rfc6749#section-4.3 ResourceOwnerPassword :: GrantTypeFlow -- | https://www.rfc-editor.org/rfc/rfc6749#section-4.4 ClientCredentials :: GrantTypeFlow -- | https://www.rfc-editor.org/rfc/rfc7523.html#section-2.1 JwtBearer :: GrantTypeFlow class ToResponseTypeValue (a :: GrantTypeFlow) toResponseTypeValue :: (ToResponseTypeValue a, IsString b) => b toResponseTypeParam :: forall a b req. (ToResponseTypeValue a, IsString b) => req a -> Map b b newtype UrnOAuthParam a UrnOAuthParam :: a -> UrnOAuthParam a -- | Grant type query parameter has association with GrantTypeFlow -- 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 newtype Scope Scope :: Text -> Scope [$sel:unScope:Scope] :: Scope -> Text newtype ClientId ClientId :: Text -> ClientId [$sel:unClientId:ClientId] :: ClientId -> Text -- | Can be either "Client Secret" or JWT base on client authentication -- method newtype ClientSecret ClientSecret :: Text -> ClientSecret [$sel:unClientSecret:ClientSecret] :: 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 [$sel:unRedirectUri:RedirectUri] :: RedirectUri -> URI newtype AuthorizeState AuthorizeState :: Text -> AuthorizeState [$sel:unAuthorizeState:AuthorizeState] :: AuthorizeState -> Text newtype Username Username :: Text -> Username [$sel:unUsername:Username] :: Username -> Text newtype Password Password :: Text -> Password [$sel:unPassword:Password] :: Password -> Text class ToQueryParam a toQueryParam :: ToQueryParam a => a -> Map Text Text class HasAuthorizeRequest (a :: GrantTypeFlow) where { data AuthorizationRequest a; type MkAuthorizationRequestResponse a; } mkAuthorizeRequestParameter :: HasAuthorizeRequest a => IdpApplication a i -> AuthorizationRequest a mkAuthorizeRequest :: HasAuthorizeRequest a => IdpApplication a i -> MkAuthorizationRequestResponse a class HasTokenRequest (a :: GrantTypeFlow) where { -- | Each GrantTypeFlow has slightly different request parameter to /token -- endpoint. data TokenRequest 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; } mkTokenRequest :: HasTokenRequest a => IdpApplication a i -> WithExchangeToken a (TokenRequest a) conduitTokenRequest :: (HasTokenRequest a, MonadIO m) => IdpApplication a i -> Manager -> WithExchangeToken a (ExceptT TokenRequestError m OAuth2Token) class HasPkceAuthorizeRequest (a :: GrantTypeFlow) mkPkceAuthorizeRequest :: (HasPkceAuthorizeRequest a, MonadIO m) => IdpApplication a i -> m (Text, CodeVerifier) class HasPkceTokenRequest (b :: GrantTypeFlow) conduitPkceTokenRequest :: (HasPkceTokenRequest b, MonadIO m) => IdpApplication b i -> Manager -> (ExchangeToken, CodeVerifier) -> ExceptT TokenRequestError m OAuth2Token class HasRefreshTokenRequest (a :: GrantTypeFlow) where { -- | https://www.rfc-editor.org/rfc/rfc6749#page-47 data RefreshTokenRequest a; } mkRefreshTokenRequest :: HasRefreshTokenRequest a => IdpApplication a i -> RefreshToken -> RefreshTokenRequest a conduitRefreshTokenRequest :: (HasRefreshTokenRequest a, MonadIO m) => IdpApplication a i -> Manager -> RefreshToken -> ExceptT TokenRequestError m OAuth2Token type family IdpUserInfo a class HasUserInfoRequest (a :: GrantTypeFlow) conduitUserInfoRequest :: (HasUserInfoRequest a, FromJSON (IdpUserInfo i)) => IdpApplication a i -> Manager -> AccessToken -> ExceptT ByteString IO (IdpUserInfo i) -- | Shall IdpApplication has a field of 'Idp a'?? data Idp a Idp :: URI -> URI -> URI -> (forall m. (FromJSON (IdpUserInfo a), MonadIO m) => Manager -> AccessToken -> URI -> ExceptT ByteString m (IdpUserInfo a)) -> Idp a [$sel:idpUserInfoEndpoint:Idp] :: Idp a -> URI [$sel:idpAuthorizeEndpoint:Idp] :: Idp a -> URI [$sel:idpTokenEndpoint:Idp] :: Idp a -> URI [$sel:idpFetchUserInfo:Idp] :: Idp a -> forall m. (FromJSON (IdpUserInfo a), MonadIO m) => Manager -> AccessToken -> URI -> ExceptT ByteString m (IdpUserInfo a) data family IdpApplication (a :: GrantTypeFlow) (i :: Type) 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 really it shall be s256 or can be omitted? -- https://datatracker.ietf.org/doc/html/rfc7636#section-4.3 [codeChallengeMethod] :: PkceRequestParam -> CodeChallengeMethod