-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/
-- | Microsoft Authentication API
--
-- Bindings to the Microsoft Identity API / Active Directory (AD) for
-- building applications that use either Authorization Code (User-facing)
-- or (App-only) authorization flows. Helper functions are provided for
-- building OAuth2 authentication flows and keep tokens transactionally
-- secure and up to date.
@package ms-auth
@version 0.3.0.0
-- | Settings for using Azure Active Directory as OAuth identity provider
--
-- Both Auth Code Grant (i.e. with browser client interaction)
-- and App-only (i.e. Client Credentials) authentication flows
-- are supported. The former is useful when a user needs to login and
-- delegate some permissions to the application (i.e. accessing personal
-- data), whereas the second is for server processes and automation
-- accounts.
module Network.OAuth2.Provider.AzureAD
data AzureAD
-- |
-- AZURE_CLIENT_ID
--
envClientId :: MonadIO f => f ClientId
-- |
-- AZURE_CLIENT_SECRET
--
envClientSecret :: MonadIO f => f ClientSecret
-- |
-- AZURE_TENANT_ID
--
envTenantId :: MonadIO f => f Text
-- | Azure OAuth application (i.e. with user consent screen)
--
-- NB : scope offline_access is ALWAYS requested
--
-- create app at https://go.microsoft.com/fwlink/?linkid=2083908
--
-- also be aware to find the right client id. see
-- https://stackoverflow.com/a/70670961
--
-- Throws AzureADException if AZURE_CLIENT_ID and/or
-- AZURE_CLIENT_SECRET credentials are not found in the
-- environment
azureADApp :: MonadIO m => Text -> [Scope] -> m (IdpApplication 'ClientCredentials AzureAD)
-- | Configuration object of the OAuth2 application
data OAuthCfg
OAuthCfg :: Text -> [Scope] -> AuthorizeState -> URI -> OAuthCfg
-- | application name
[$sel:oacAppName:OAuthCfg] :: OAuthCfg -> Text
-- | OAuth2 and OIDC scopes
[$sel:oacScopes:OAuthCfg] :: OAuthCfg -> [Scope]
-- | OAuth2 state (a random string,
-- https://www.rfc-editor.org/rfc/rfc6749#section-10.12 )
[$sel:oacAuthState:OAuthCfg] :: OAuthCfg -> AuthorizeState
-- | OAuth2 redirect URI
[$sel:oacRedirectURI:OAuthCfg] :: OAuthCfg -> URI
-- |
-- https://learn.microsoft.com/en-us/azure/active-directory/develop/userinfo
data AzureADUser
-- | Azure OAuth application (i.e. with user consent screen)
--
-- NB : scopes openid and offline_access are ALWAYS
-- requested since the library assumes we have access to refresh tokens
-- and ID tokens
--
-- Reference on Microsoft Graph permissions :
-- https://learn.microsoft.com/en-us/graph/permissions-reference
--
-- create app at https://go.microsoft.com/fwlink/?linkid=2083908
--
-- also be aware to find the right client id. see
-- https://stackoverflow.com/a/70670961
--
-- Throws AzureADException if AZURE_CLIENT_ID and/or
-- AZURE_CLIENT_SECRET credentials are not found in the
-- environment
azureOAuthADApp :: MonadIO m => OAuthCfg -> m (IdpApplication 'AuthorizationCode AzureAD)
data AzureADException
AADNoEnvVar :: String -> AzureADException
instance GHC.Show.Show Network.OAuth2.Provider.AzureAD.AzureAD
instance GHC.Classes.Eq Network.OAuth2.Provider.AzureAD.AzureAD
instance GHC.Show.Show Network.OAuth2.Provider.AzureAD.AzureADUser
instance GHC.Classes.Ord Network.OAuth2.Provider.AzureAD.AzureADUser
instance GHC.Classes.Eq Network.OAuth2.Provider.AzureAD.AzureADUser
instance Data.Aeson.Types.FromJSON.FromJSON Network.OAuth2.Provider.AzureAD.AzureADUser
instance GHC.Exception.Type.Exception Network.OAuth2.Provider.AzureAD.AzureADException
instance GHC.Show.Show Network.OAuth2.Provider.AzureAD.AzureADException
-- | MS Identity user session based on OAuth tokens
--
-- The library supports the following authentication scenarios :
--
--
--
-- and provides functions to keep tokens up to date in the background.
module Network.OAuth2.Session
-- | App has (at most) one token at a time
type Token t = TVar (Maybe t)
-- | Create an empty Token store
newNoToken :: MonadIO m => m (Token t)
-- | Delete the current token
expireToken :: MonadIO m => Token t -> m ()
-- | Read the current value of the token
readToken :: MonadIO m => Token t -> m (Maybe t)
-- | Fetch an OAuth token and keep it updated. Should be called as a first
-- thing in the app
--
-- NB : forks a thread in the background
--
--
-- https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
fetchUpdateToken :: MonadIO m => IdpApplication 'ClientCredentials AzureAD -> Token OAuth2Token -> Manager -> m ()
-- | DefaultAzureCredential mechanism as in the Python SDK
-- https://pypi.org/project/azure-identity/
--
-- Order of authentication attempts:
--
-- 1) token request with client secret
--
-- 2) token request via managed identity (App Service and Azure
-- Functions)
-- https://learn.microsoft.com/en-us/azure/app-service/overview-managed-identity?tabs=portal%2Chttp#rest-endpoint-reference
defaultAzureCredential :: MonadIO m => String -> String -> IdpApplication 'ClientCredentials AzureAD -> Token OAuth2Token -> Manager -> m ()
-- | Login endpoint
--
-- see azureADApp
loginEndpoint :: MonadIO m => IdpApplication 'AuthorizationCode AzureAD -> RoutePattern -> Scotty m ()
-- | The identity provider redirects the client to the reply
-- endpoint as part of the OAuth flow :
-- https://learn.microsoft.com/en-us/graph/auth-v2-user?view=graph-rest-1.0&tabs=http#authorization-response
--
-- NB : forks a thread per logged in user to keep their tokens up to date
replyEndpoint :: MonadIO m => IdpApplication 'AuthorizationCode AzureAD -> Tokens UserSub OAuth2Token -> Manager -> RoutePattern -> Scotty m ()
-- | transactional token store
type Tokens uid t = TVar (TokensData uid t)
-- | Create an empty Tokens object
newTokens :: (MonadIO m, Ord uid) => m (Tokens uid t)
-- | sub field
data UserSub
-- | Look up a user identifier and return their current token, if any
lookupUser :: (MonadIO m, Ord uid) => Tokens uid t -> uid -> m (Maybe t)
-- | Remove a user, i.e. they will have to authenticate once more
expireUser :: (MonadIO m, Ord uid) => Tokens uid t -> uid -> m ()
-- | return a list representation of the Tokens object
tokensToList :: MonadIO m => Tokens k a -> m [(k, a)]
-- | Decode the App Service ID token header
-- X-MS-TOKEN-AAD-ID-TOKEN, look its user up in the local token
-- store, supply token t to continuation. If the user
-- sub cannot be found in the token store the browser is
-- redirected to the login URI.
--
-- Special case of aadHeaderIdToken
withAADUser :: MonadIO m => Tokens UserSub t -> Text -> (t -> Action m ()) -> Action m ()
type Scotty = ScottyT Text
type Action = ActionT Text
instance GHC.Classes.Eq Network.OAuth2.Session.OAuthSessionError
instance (GHC.Show.Show uid, GHC.Show.Show t) => GHC.Show.Show (Network.OAuth2.Session.TokensData uid t)
instance (GHC.Classes.Eq uid, GHC.Classes.Eq t) => GHC.Classes.Eq (Network.OAuth2.Session.TokensData uid t)
instance GHC.Exception.Type.Exception Network.OAuth2.Session.OAuthSessionError
instance GHC.Show.Show Network.OAuth2.Session.OAuthSessionError
-- | Functions for implementing Azure AD-based authentication
--
-- Both Auth Code Grant (i.e. with browser client interaction)
-- and App-only (i.e. Client Credentials) authentication flows
-- are supported. The former is useful when a user needs to login and
-- delegate some permissions to the application (i.e. accessing personal
-- data), whereas the second is for server processes and automation
-- accounts.
module MSAuth
-- | Load, parse and apply a .env file
--
-- NB : overwrites any preexisting env vars
--
-- NB2 : if the .env file is not found the program continues
-- (i.e. this function is a no-op in that case)
applyDotEnv :: MonadIO m => Maybe FilePath -> m ()
-- | App has (at most) one token at a time
type Token t = TVar (Maybe t)
-- | Create an empty Token store
newNoToken :: MonadIO m => m (Token t)
-- | Delete the current token
expireToken :: MonadIO m => Token t -> m ()
-- | Read the current value of the token
readToken :: MonadIO m => Token t -> m (Maybe t)
-- | Fetch an OAuth token and keep it updated. Should be called as a first
-- thing in the app
--
-- NB : forks a thread in the background
--
--
-- https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
fetchUpdateToken :: MonadIO m => IdpApplication 'ClientCredentials AzureAD -> Token OAuth2Token -> Manager -> m ()
-- | DefaultAzureCredential mechanism as in the Python SDK
-- https://pypi.org/project/azure-identity/
--
-- Order of authentication attempts:
--
-- 1) token request with client secret
--
-- 2) token request via managed identity (App Service and Azure
-- Functions)
-- https://learn.microsoft.com/en-us/azure/app-service/overview-managed-identity?tabs=portal%2Chttp#rest-endpoint-reference
defaultAzureCredential :: MonadIO m => String -> String -> IdpApplication 'ClientCredentials AzureAD -> Token OAuth2Token -> Manager -> m ()
-- | Login endpoint
--
-- see azureADApp
loginEndpoint :: MonadIO m => IdpApplication 'AuthorizationCode AzureAD -> RoutePattern -> Scotty m ()
-- | The identity provider redirects the client to the reply
-- endpoint as part of the OAuth flow :
-- https://learn.microsoft.com/en-us/graph/auth-v2-user?view=graph-rest-1.0&tabs=http#authorization-response
--
-- NB : forks a thread per logged in user to keep their tokens up to date
replyEndpoint :: MonadIO m => IdpApplication 'AuthorizationCode AzureAD -> Tokens UserSub OAuth2Token -> Manager -> RoutePattern -> Scotty m ()
-- | transactional token store
type Tokens uid t = TVar (TokensData uid t)
-- | Create an empty Tokens object
newTokens :: (MonadIO m, Ord uid) => m (Tokens uid t)
-- | sub field
data UserSub
-- | Look up a user identifier and return their current token, if any
lookupUser :: (MonadIO m, Ord uid) => Tokens uid t -> uid -> m (Maybe t)
-- | Remove a user, i.e. they will have to authenticate once more
expireUser :: (MonadIO m, Ord uid) => Tokens uid t -> uid -> m ()
-- | return a list representation of the Tokens object
tokensToList :: MonadIO m => Tokens k a -> m [(k, a)]
-- | Decode the App Service ID token header
-- X-MS-TOKEN-AAD-ID-TOKEN, look its user up in the local token
-- store, supply token t to continuation. If the user
-- sub cannot be found in the token store the browser is
-- redirected to the login URI.
--
-- Special case of aadHeaderIdToken
withAADUser :: MonadIO m => Tokens UserSub t -> Text -> (t -> Action m ()) -> Action m ()
type Scotty = ScottyT Text
type Action = ActionT Text