Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/obsidiansystems/obelisk-oauth
https://github.com/obsidiansystems/obelisk-oauth
haskell oauth
Last synced: 2 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/obsidiansystems/obelisk-oauth
- Owner: obsidiansystems
- Created: 2019-02-19T15:24:52.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2023-07-17T15:47:28.000Z (over 1 year ago)
- Last Synced: 2024-08-03T15:06:34.881Z (5 months ago)
- Topics: haskell, oauth
- Language: Haskell
- Size: 92.8 KB
- Stars: 12
- Watchers: 31
- Forks: 3
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
- Changelog: ChangeLog.md
Awesome Lists containing this project
README
# obelisk-oauth
## Setup
This repo contains two packages: `obelisk-oauth-common` and `obelisk-oauth-backend`.
An example usage of these packages is available in the `example` directory.
To add these packages to your obelisk project, follow the steps below from your obelisk project root (i.e., the folder you ran `ob init` in).
### Add dependency thunk
```bash
$ mkdir dep
$ cd dep
$ git clone [email protected]:obsidian.systems/obelisk-oauth
$ ob thunk pack obelisk-oauth
```The last step here (`ob thunk pack`) replaces the cloned repository with a "thunk" that contains all the information obelisk needs to fetch/use the repository when needed.
Check out `ob thunk --help` to learn more about working with thunks.
### Add packages to default.nix
Your skeleton project's `default.nix` uses the [reflex-platform project infrastructure](https://github.com/reflex-frp/reflex-platform/blob/develop/project/default.nix). We can use the [`packages` field](https://github.com/reflex-frp/reflex-platform/blob/develop/project/default.nix#L53-L58) of the project configuration to add our custom packages, as follows:
```nix
project ./. ({ hackGet, ... }: {
packages = {
obelisk-oauth-common = (hackGet ./dep/obelisk-oauth) + "/common";
obelisk-oauth-backend = (hackGet ./dep/obelisk-oauth) + "/backend";
... # other configuration goes here
};
})
```Be sure to add `hackGet` to the list of items to bring into scope. `hackGet` is a nix function defined in reflex-platform that takes a path that points to either a source directory or a packed thunk (in other words, it takes a path to a thunk but doesn't care whether it's packed or unpacked). It produces a path to the source (unpacked if necessary). Once we've got that path, we just need to append the subdirectory paths to the individual repos contained in this repository.
### Add packages to cabal files
Finally, add `obelisk-oauth-common` to the `build-depends` field of `common/common.cabal` and add `obelisk-oauth-common` and `obelisk-oauth-backend` to the `build-depends` field of the library stanza in `backend/backend.cabal`.
## `Common.Route` + `Obelisk.OAuth.Authorization`
Add a sub-route to your backend route and embed the provided OAuth route:
```haskell
data BackendRoute :: * -> * where
BackendRoute_Missing :: BackendRoute ()
BackendRoute_Api :: BackendRoute ()
BackendRoute_OAuth :: BackendRoute (R OAuth)
```Your backend route encoder should handle this case:
```haskell
...
pathComponentEncoder $ \case
BackendRoute_OAuth -> PathSegment "oauth" oauthRouteEncoder
...
```## Frontend
On the frontend, you need to produce an authorization request link with the appropriate callback embedded.
For example:
```haskell
do
let r = AuthorizationRequest
{ _authorizationRequest_responseType = AuthorizationResponseType_Code
, _authorizationRequest_clientId = clientId
, _authorizationRequest_redirectUri = Just BackendRoute_OAuth
, _authorizationRequest_scope = []
, _authorizationRequest_state = Just "none"
}
grantHref = authorizationRequestHref "https://app.asana.com/-/oauth_authorize" route checkedEncoder r
elAttr "a" ("href" =: grantHref) $ text "Authorize with Asana"
```## Backend
In your backend handler, you'll need to handle the OAuth sub-route you created:
```haskell
...
serve $ \case
BackendRoute_OAuth :/ oauthRoute -> case oauthRoute of
OAuth_RedirectUri :/ redirectParams -> case redirectParams of
Nothing -> liftIO $ error "Expected to receive the authorization code here"
Just (RedirectUriParams code mstate) -> do
let t = TokenRequest
{ _tokenRequest_grant = TokenGrant_AuthorizationCode $ T.encodeUtf8 code
, _tokenRequest_clientId = clientId -- Get this from the OAuth authorization server
, _tokenRequest_clientSecret = clientSecret -- Get this from the OAuth authorization server
, _tokenRequest_redirectUri = BackendRoute_OAuth
}
reqUrl = "https://app.asana.com/-/oauth_token"
rsp <- liftIO $ flip httpLbs tlsMgr =<< getOauthToken reqUrl route checkedEncoder t
-- ^ this response should include the access token and probably a refresh token
...
```