-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/
-- | Tutorial for using hoauth2
--
-- Tutorial to demostrate how to use hoauth2 to implement OAuth2 flow in
-- an web Application.
@package hoauth2-tutorial
@version 0.1.1
-- | If you're hurry, go check source code directly.
--
--
Configure your OAuth2 provider
--
-- Pick which OAuth2 provider you'd to use, e.g. Google, Github, Auth0
-- etc. Pretty much all standard OAuth2 provider has developer portal to
-- guide developer to use oauth2 flow. So read it through if you're
-- unfamiliar OAuth2 before. Often time, those documents will guide you
-- how to create an Application which has credentials (e.g.
-- client_id and client_secret for a web application),
-- which will be used to authenticate your service (replying party) with
-- server.
--
-- For some OIDC providers, you may even be able to find out those URLs
-- from a well-known endpoint.
--
--
-- https://BASE_DOMAIN/.well-known/openid-configuration
--
--
-- In this tutorial, I choose Auth0, which is one of existing OAuth2/OIDC
-- Providers in the market. This is the API Docs
-- https://auth0.com/docs/api
--
-- Generate Authorization URL.
--
-- OAuth2 starts with authorization.
--
-- To generate an authorization URL, call method authorizationUrl,
-- then call appendQueryParams to append additional query
-- parameters, e.g. state, scope etc.
--
-- That method will also automatically append following query parameter
-- to the authorization url.
--
--
-- client_id = xxx -- client id of your Application credential you got previously
-- response_type = code -- must be for authorization request
-- redirect_uri = xxx -- where does the server (provider) send back the authorization code.
-- -- You have to config this when creating Application at previous step.
--
--
-- The generated URL looks like
--
--
-- https://DOMAIN/path/to/authorize?client_id=xxx&response_type=code&redirect_uri=xxx&state=xxx&scope=xxx&..
--
--
-- Notes: As of today, hoauth2 only supports Code
-- Grant.
--
-- Redirect user to the Authorization URL
--
-- Now you need to have your user to navigate to that URL to kick off
-- OAuth flow.
--
-- There are different ways to redirect user to the authorizeUrl.
--
-- e.g.
--
--
-- - Display as anchor link directly at UI so that user can click
-- it.
-- - Create your own login endpoint, e.g. /login, which then
-- 302 to the authorizeUrl.
--
--
-- In this tutorial, I choose the second option. For instance this is how
-- indexH is implemented.
--
--
-- >>> setHeader "Location" (uriToText authorizeUrl)
--
-- >>> status status302
--
--
-- Obtain Access Token
--
-- When user navigates to authorizeUrl, user will be prompt for
-- login against the OAuth provider.
--
-- After an successful login there, user will be redirect back to your
-- Application's redirect_uri with code in the query
-- parameter.
--
-- With this code, we could exchange for an Access Token.
--
-- Also you'd better to validate the state is exactly what you
-- pass in the authorizeUrl. OAuth2 provider expects to send the
-- exact state back in the redirect request.
--
-- To obtain an Access Token, you could call fetchAccessToken,
-- which essentially takes the authorization code, make request
-- to OAuth2 provider's /token endpoint to get an Access Token,
-- plus some other information (see details at OAuth2Token).
--
-- fetchAccessToken returns ExceptT (OAuth2Error Errors) m
-- OAuth2Token However Scotty, which is web framework I used to
-- build this tutorial, requires error as Text hence the transform with
-- oauth2ErrorToText
--
-- Once we got the OAuth2Token (which actually deserves an better
-- name like TokenResponse), we could get the actual
-- accessToken of out it, use which to make API requests to
-- resource server (often time same as the authorization server)
--
-- Network.OAuth.OAuth2.HttpClient provides a few handy method to
-- send such API request. For instance,
--
--
-- authGetJSON -- Makes GET request and decode response as JSON, with access token appended in Authorization http header.
-- authPostJSON -- Similar but does POST request
--
--
-- In this tutorial, it makes request to auth0UserInfoUri to fetch
-- Auth0 user information so application knows who did the authorize.
--
-- The end
--
-- That's it! Congratulations make thus far!
--
-- If you're interested more of OAuth2, keep reading on
-- https://www.oauth.com/, which provides a nice guide regarding
-- what is OAuth2 and various use cases.
module HOAuth2Tutorial
auth0 :: OAuth2
authorizeUrl :: URI
-- | You'll need to find out an better to create state which is
-- recommended in
-- https://www.rfc-editor.org/rfc/rfc6749#section-10.12
randomStateValue :: ByteString
-- | Endpoint for fetching user profile using access token
auth0UserInfoUri :: URI
-- | Auth0 user
-- https://auth0.com/docs/api/authentication#get-user-info
data Auth0User
Auth0User :: Text -> Text -> Text -> Auth0User
[name] :: Auth0User -> Text
[email] :: Auth0User -> Text
[sub] :: Auth0User -> Text
-- | The scotty application
app :: IO ()
-- | / endpoint handler
indexH :: IORef (Maybe Auth0User) -> ActionM ()
-- | /login endpoint handler
loginH :: ActionM ()
-- | /logout endpoint handler
logoutH :: IORef (Maybe Auth0User) -> ActionM ()
-- | oauth2callback endpoint handler
callbackH :: IORef (Maybe Auth0User) -> ActionM ()
uriToText :: URI -> Text
bslToText :: ByteString -> Text
paramValue :: Text -> [Param] -> Either Text Text
-- | Lift ExceptT to ActionM which is basically the handler Monad in
-- Scotty.
excepttToActionM :: Show a => ExceptT Text IO a -> ActionM a
oauth2ErrorToText :: OAuth2Error Errors -> Text
instance GHC.Generics.Generic HOAuth2Tutorial.Auth0User
instance GHC.Show.Show HOAuth2Tutorial.Auth0User
instance Data.Aeson.Types.FromJSON.FromJSON HOAuth2Tutorial.Auth0User