-- 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. -- --
    --
  1. Display as anchor link directly at UI so that user can click -- it.
  2. --
  3. Create your own login endpoint, e.g. /login, which then -- 302 to the authorizeUrl.
  4. --
-- -- 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