Yesod.Auth.OAuth2

OAuth2 AuthPlugins for Yesod.

Usage

import Yesod.Auth
import Yesod.Auth.OAuth2.GitHub

instance YesodAuth App where
    -- ...

    authPlugins _ = [oauth2GitHub clientId clientSecret]

clientId :: Text
clientId = "..."

clientSecret :: Text
clientSecret = "..."

Some plugins, such as GitHub and Slack, have scoped functions for requesting additional information:

oauth2SlackScoped [SlackBasicScope, SlackEmailScope] clientId clientSecret

Working with Extra Data

We put the minimal amount of user data possible in credsExtra – just enough to support you parsing or fetching additional data yourself.

For example, if you work with GitHub and GitHub user profiles, you likely already have a model and a way to parse the /user response. Rather than duplicate all that in our library, we try to make it easy for you to re-use that code yourself:

authenticate creds = do
    let
        -- You can run your own FromJSON parser on the response we already have
        eGitHubUser :: Either String GitHubUser
        eGitHubUser = getUserResponseJSON creds

        -- Avert your eyes, simplified example
        Just accessToken = getAccessToken creds
        Right githubUser = eGitHubUser

    -- Or make followup requests using our access token
    runGitHub accessToken $ userRepositories githubUser

    -- Or store it for later
    insert User
        { userIdent = credsIdent creds
        , userAccessToken = accessToken
        }

NOTE: Avoid looking up values in credsExtra yourself; prefer the provided get functions. The data representation itself is no longer considered public API.

Local Providers

If we don’t supply a “Provider” (e.g. GitHub, Google, etc) you need, you can write your own using our provided Prelude:

import Yesod.Auth.OAuth2.Prelude

pluginName :: Text
pluginName = "mysite"

oauth2MySite :: YesodAuth m => Text -> Text -> AuthPlugin m
oauth2MySite clientId clientSecret =
    authOAuth2 pluginName oauth2 $ \manager token -> do
        -- Fetch a profile using the manager and token, leave it a ByteString
        userResponse <- -- ...

        -- Parse it to your preferred identifier, e.g. with Data.Aeson
        userId <- -- ...

        -- See authGetProfile for the typical case

        pure Creds
            { credsPlugin = pluginName
            , credsIdent = userId
            , credsExtra = setExtra token userResponse
            }
  where
    oauth2 = OAuth2
        { oauthClientId = clientId
        , oauthClientSecret = Just clientSecret
        , oauthOAuthorizeEndpoint = "https://mysite.com/oauth/authorize"
        , oauthAccessTokenEndpoint = "https://mysite.com/oauth/token"
        , oauthCallback = Nothing
        }

The Prelude module is considered public API, though we may build something higher-level that is more convenient for this use-case in the future.

Development & Tests

stack setup
stack build --dependencies-only
stack build --pedantic --test

Please also run HLint and Weeder before submitting PRs.


CHANGELOG | LICENSE

Changes

Unreleased

None

v0.6.1.7

  • Relax upper bounds on hoauth2 and http-client

v0.6.1.6

  • Revert back to Authorization-header-only fetchAccessToken function
  • Add authOAuth2' and authOAuth2Widget', which use fetchAccessToken2

v0.6.1.5

  • Update to GHC-8.8, and hoauth2-1.14
  • Drop CI-backed support for GHC-8.4

v0.6.1.4

  • Tighten upper bound on hoauth2

v0.6.1.3

  • Replace System.Random state token generation with cryptonite
  • Allow aeson-1.5 and hoauth2-1.14
  • Add WordPress.com provider @nbloomf

v0.6.1.2

  • Don’t report our own errors like OAuth2 ErrorResponses

v0.6.1.1

  • Added AzureAD provider
  • COMPATIBILITY: Use hoauth2-1.8.1
  • COMPATIBILITY: Test with GHC 8.6.3, and not 8.2

v0.6.1.0

  • Allow http-client-0.6

v0.6.0.0

  • Remove deprecated Github module

v0.5.3.0

  • Allow aeson-1.4 and hoauth2-1.8

v0.5.2.0

  • InvalidProfileResponse was replaced with different, situation-specific constructors; the exception type is considered internal API, but end-users may see them in logs, or if they (unexpectedly) escape our error-handling
  • Errors during log-in no longer result in 4XX or 5XX responses; they now redirect to LoginR with the exception details logged and something user-appropriate displayed via setMessage

v0.5.1.0

  • Added GitLab provider
  • Added properly-named GitHub module, deprecated Github
  • Store refreshToken in credsExtra

v0.5.0.0

  • COMPATIBILITY: Allow and require yesod-1.6
  • COMPATIBILITY: Stop testing GHC 8.0 on CI

v0.4.1.0

  • Check for errors in callback query params, as described in the spec

v0.4.0.1

  • COMPATIBILITY: Allow http-types-0.12

v0.4.0.0

  • COMPATIBILITY: Allow aeson-1.3

  • COMPATIBILITY: Dropped a lot of information from credsExtra:

    TL;DR: you’ll no longer find things like username or email as keys in the credsExtra map. Instead, you’ll find the encoded profile response we received and the OAuth access token. You can/should do your own decoding or make your own follow-up requests to get extra data about your users.

    This reduced a lot of complexity, likely duplication between our decoding and yours, and (I think) makes the library easier to use.

  • COMPATIBILITY: Support GHC-8.2

  • COMPATIBILITY: Drop (claimed, but never tested) support for GHC-7.8 & 7.10

  • LICENSE: fixed vague licensing (MIT now)

v0.3.1

  • Internal project cleanup

v0.3.0

  • COMPATIBILITY: Use hoauth2-1.3

v0.2.4

  • FIX: Update Nylas provider
  • NEW: Battle.Net provider
  • NEW: Bitbucket provider
  • NEW: Salesforce provider

v0.2.1

  • FIX: Fix collision in GitHub email / public_email extras value

v0.2.0

v0.1.10

  • FIX: location is optional in GitHub response

v0.1.9

v0.1.8

  • COMPATIBILITY: Allow aeson-0.11 (@k-bx)

v0.1.7

  • NEW: Prefer primary email in GitHub provider
  • NEW: Include public_email in GitHub extras response
  • REMOVED: Remove Twitter provider

v0.1.6

  • NEW: Nicer error message on invalid code (@silky)

v0.1.5

  • FIX: Incorrect state parameter handling

v0.1.4

  • FIX: Use newer Nylas endpoint

v0.1.3

  • NEW: EveOnline provider (@Drezil)
  • NEW: Nylas provider (@bts)

v0.1.2

  • NEW: A more different Google provider (@ssaavedra)

v0.1.1

  • NEW: Twitter provider

v0.1.0

  • REMOVED: Google provider, use Yesod.Auth.GoogleEmail2
  • CHANGED: Learn was renamed to Upcase
  • COMPATIBILITY: Drop support for GHC-6
  • COMPATIBILITY: Support GHC-7.10

v0.0.12

  • COMPATIBILITY: Allow transformers-0.4 (@snoyberg)

v0.0.11

v0.0.10

v0.0.9

v0.0.8

  • FIX: Username may be missing in GitHub responses (@skade)

v0.0.7

  • NEW: Scope support in GitHub provider (@skade)

v0.0.6

  • NEW: GitHub provider (@freiric)
  • COMPATIBILITY: flag-driven network/network-uri dependency

v0.0.5.1

  • DOCUMENTATION: fix data declaration, allows Haddocks to build

v0.0.5

  • COMPATIBILITY: Allow yesod-core-1.3 and target yesod-auth-1.3 (@maxcan)
  • COMPATIBILITY: Target haouth2-0.4 (@katyo)

v0.0.4

  • COMPATIBILITY: Allow text-1.*
  • COMPATIBILITY: Allow lifted-base-0.2.*

v0.0.3

  • FIX: replace error crash with throwIO exception

v0.0.2

  • Various documentation fixes.

v0.0.1

Initial version. Maintainer-ship taken over by @pbrisbin.