gogol
gogol copied to clipboard
When to use Network.Google.Auth.authorize & why doesn't Credentials.FromClient have AccessToken & RefreshToken?
I've been trying to wrap my head around this one:
- After the oauth flow of an "installed application", the user is given a one-time code, which he/she is supposed to share with the application
- The application then exchanges the one-time code for an oauth access-token & refresh-token:
oauthReturn :: Maybe Text -> AppM Text
oauthReturn Nothing = throwIO $ OAuthError "Did not receive `code` as a URL queryParam at the end of oauth flow"
oauthReturn (Just code_) = do
env <- ask
let oauthCreds = Google.allow (plusLoginScope Google.! userInfoEmailScope) $ Google.FromClient (env ^. oAuthClient) (OAuthCode code_)
auth <- Google.exchange oauthCreds (env ^. googleLogger) (env ^. googleManager)
pure ([qc|{code_} has been exchanged to {_token auth}|])
- After that, if one wants to use
Network.Google.send
along withNetwork.Google.runGoogle
, one needs to construct a value of typeNetwork.Google.Env
. Here's the type signature ofnewEnvWith
:
newEnvWith :: (MonadIO m, MonadCatch m, AllowScopes s) => Credentials s -> Logger -> Manager -> m (Env s)
- The only type related to oauth authentication is
Credentials s
, and none of the constructors ofCredentials s
bother with taking the oauth access-token & refresh-token obtained from the step above!
What am I missing here?
Okay, managed to figure out how to create an Env
at the end of the oauth flow, which calls exchange
internally to get the access/refresh tokens:
oauthReturn :: Maybe Text -> AppM Text
oauthReturn Nothing = throwIO $ OAuthError "Did not receive `code` as a URL queryParam at the end of oauth flow"
oauthReturn (Just code_) = do
env <- ask
let oauthCreds = Google.allow (plusLoginScope Google.! userInfoEmailScope) $ Google.FromClient (env ^. oAuthClient) (OAuthCode code_)
googleEnv <- Google.newEnvWith oauthCreds (env ^. googleLogger) (env ^. googleManager)
auth <- retrieveAuthFromStore $ googleEnv ^. Google.envStore
pure ([qc|{code_} has been exchanged to {_token auth}|])
I experienced a similar problem with this as well. Creating Credentials
from an auth code is fine, but in my case I wanted to create them directly with the refresh token which wasn't possible.
What I ended up doing is to generate the tokens with FromClient
, exchange
the result to get an Auth
record, convert to AuthorizedUser
with authToAuthorizedUser
and then saveAuthorizedUser
in a file. After that you can use the file to generate the Credentals
.
The file itself is stored as a json with the client_id
, client_secret
and refresh_token
so it's perfectly possible to ignore the above steps and just use that, but it would be nice if we could get a way of skipping the file and just getting a Credentials
record from a client and a refresh token.