hoauth2's fetchAccessToken provides credentials in the Authorization header, while fetchAccessToken2 provides them in that header but also the POST body. It was discovered that some providers only support one or the other, so using fetchAccessToken2 would be preferred since it should work with either. This happened in #129. However, we discovered at least one provider (Okta) that actively rejects requests unless they're supplying credentials in exactly one place: Cannot supply multiple client credentials. Use one of the following: credentials in the Authorization header, credentials in the post body, or a client_assertion in the post body." This patch reverts back to fetchAccessToken, but makes it possible to for client to use fetchAccessToken2 if necessary via alternative functions. |
||
|---|---|---|
| .circleci | ||
| example | ||
| src | ||
| test | ||
| .env.example | ||
| .gitignore | ||
| .hlint.yaml | ||
| .stylish-haskell.yaml | ||
| CHANGELOG.md | ||
| LICENSE | ||
| Makefile | ||
| package.yaml | ||
| README.md | ||
| Setup.lhs | ||
| stack-lts-13.2.yaml | ||
| stack-lts-13.2.yaml.lock | ||
| stack-lts-16.10.yaml | ||
| stack-lts-16.10.yaml.lock | ||
| stack-nightly.yaml | ||
| stack-nightly.yaml.lock | ||
| stack.yaml | ||
| stack.yaml.lock | ||
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.