Copyright | Hasura |
---|---|
Safe Haskell | None |
Language | Haskell2010 |
This module implements the bulk of Hasura's JWT capabilities and interactions.
Its main point of non-testing invocation is Auth
.
It exports both processJwt
and processJwt_
with processJwt_
being the
majority of the implementation with the JWT Token processing function
passed in as an argument in order to enable mocking in test-code.
In processJwt_
, prior to validation of the token, first the token locations
and issuers are reconciled. Locations are either specified as auth or
cookie (with cookie name) or assumed to be auth. Issuers can be omitted or
specified, where an omitted configured issuer can match any issuer specified by
a request.
If none match, then this is considered an no-auth request, if one matches, then normal token auth is performed, and if multiple match, then this is considered an ambiguity error.
Synopsis
- newtype RawJWT = RawJWT ByteString
- data JWTClaimsFormat
- data JWTHeader
- = JHAuthorization
- | JHCookie Text
- defaultClaimsFormat :: JWTClaimsFormat
- allowedRolesClaim :: SessionVariable
- defaultRoleClaim :: SessionVariable
- defaultClaimsNamespace :: Text
- data JWTCustomClaimsMapValueG v
- = JWTCustomClaimsMapJSONPath !JSONPath !(Maybe v)
- | JWTCustomClaimsMapStatic !v
- type JWTCustomClaimsMapDefaultRole = JWTCustomClaimsMapValueG RoleName
- type JWTCustomClaimsMapAllowedRoles = JWTCustomClaimsMapValueG [RoleName]
- type JWTCustomClaimsMapValue = JWTCustomClaimsMapValueG SessionVariableValue
- type CustomClaimsMap = HashMap SessionVariable JWTCustomClaimsMapValue
- data JWTCustomClaimsMap = JWTCustomClaimsMap {}
- data JWTNamespace
- = ClaimNsPath JSONPath
- | ClaimNs Text
- data JWTClaims
- newtype StringOrURI = StringOrURI {
- unStringOrURI :: StringOrURI
- data JWTConfig = JWTConfig {
- jcKeyOrUrl :: !(Either JWK URI)
- jcAudience :: !(Maybe Audience)
- jcIssuer :: !(Maybe StringOrURI)
- jcClaims :: !JWTClaims
- jcAllowedSkew :: !(Maybe NominalDiffTime)
- jcHeader :: !(Maybe JWTHeader)
- data JWTCtx = JWTCtx {
- jcxKey :: !(IORef JWKSet)
- jcxAudience :: !(Maybe Audience)
- jcxIssuer :: !(Maybe StringOrURI)
- jcxClaims :: !JWTClaims
- jcxAllowedSkew :: !(Maybe NominalDiffTime)
- jcxHeader :: !JWTHeader
- data HasuraClaims = HasuraClaims {
- _cmAllowedRoles :: ![RoleName]
- _cmDefaultRole :: !RoleName
- jwkRefreshCtrl :: (MonadIO m, MonadBaseControl IO m, HasReporter m) => Logger Hasura -> Manager -> URI -> IORef JWKSet -> DiffTime -> m void
- updateJwkRef :: (MonadIO m, MonadBaseControl IO m, MonadError JwkFetchError m, MonadTrace m) => Logger Hasura -> Manager -> URI -> IORef JWKSet -> m (Maybe NominalDiffTime)
- determineJwkExpiryLifetime :: forall m. (MonadIO m, MonadError JwkFetchError m) => m UTCTime -> Logger Hasura -> ResponseHeaders -> m (Maybe NominalDiffTime)
- type ClaimsMap = HashMap SessionVariable Value
- decodeClaimsSet :: RawJWT -> Maybe ClaimsSet
- tokenIssuer :: RawJWT -> Maybe StringOrURI
- processJwt :: (MonadIO m, MonadError QErr m) => [JWTCtx] -> RequestHeaders -> Maybe RoleName -> m (UserInfo, Maybe UTCTime, [Header])
- type AuthTokenLocation = JWTHeader
- processJwt_ :: MonadError QErr m => (JWTCtx -> ByteString -> m (ClaimsMap, Maybe UTCTime)) -> (RawJWT -> Maybe StringOrURI) -> (JWTCtx -> JWTHeader) -> [JWTCtx] -> RequestHeaders -> Maybe RoleName -> m (UserInfo, Maybe UTCTime, [Header])
- processHeaderSimple :: (MonadIO m, MonadError QErr m) => JWTCtx -> ByteString -> m (ClaimsMap, Maybe UTCTime)
- parseClaimsMap :: MonadError QErr m => ClaimsSet -> JWTClaims -> m ClaimsMap
- verifyJwt :: (MonadError JWTError m, MonadIO m) => JWTCtx -> RawJWT -> m ClaimsSet
- parseHasuraClaims :: forall m. MonadError QErr m => ClaimsMap -> m HasuraClaims
- parseJwtClaim :: (FromJSON a, MonadError QErr m) => Value -> Text -> m a
Documentation
data JWTClaimsFormat Source #
Instances
Eq JWTClaimsFormat Source # | |
Defined in Hasura.Server.Auth.JWT (==) :: JWTClaimsFormat -> JWTClaimsFormat -> Bool # (/=) :: JWTClaimsFormat -> JWTClaimsFormat -> Bool # | |
Show JWTClaimsFormat Source # | |
Defined in Hasura.Server.Auth.JWT showsPrec :: Int -> JWTClaimsFormat -> ShowS # show :: JWTClaimsFormat -> String # showList :: [JWTClaimsFormat] -> ShowS # | |
FromJSON JWTClaimsFormat Source # | |
Defined in Hasura.Server.Auth.JWT parseJSON :: Value -> Parser JWTClaimsFormat parseJSONList :: Value -> Parser [JWTClaimsFormat] | |
ToJSON JWTClaimsFormat Source # | |
Defined in Hasura.Server.Auth.JWT toJSON :: JWTClaimsFormat -> Value toEncoding :: JWTClaimsFormat -> Encoding toJSONList :: [JWTClaimsFormat] -> Value toEncodingList :: [JWTClaimsFormat] -> Encoding |
JHAuthorization | |
JHCookie Text |
Instances
Eq JWTHeader Source # | |
Show JWTHeader Source # | |
Generic JWTHeader Source # | |
Hashable JWTHeader Source # | |
Defined in Hasura.Server.Auth.JWT | |
FromJSON JWTHeader Source # | |
Defined in Hasura.Server.Auth.JWT parseJSON :: Value -> Parser JWTHeader parseJSONList :: Value -> Parser [JWTHeader] | |
ToJSON JWTHeader Source # | |
Defined in Hasura.Server.Auth.JWT toEncoding :: JWTHeader -> Encoding toJSONList :: [JWTHeader] -> Value toEncodingList :: [JWTHeader] -> Encoding | |
type Rep JWTHeader Source # | |
Defined in Hasura.Server.Auth.JWT type Rep JWTHeader = D1 ('MetaData "JWTHeader" "Hasura.Server.Auth.JWT" "graphql-engine-1.0.0-inplace" 'False) (C1 ('MetaCons "JHAuthorization" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "JHCookie" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Text))) |
defaultClaimsNamespace :: Text Source #
data JWTCustomClaimsMapValueG v Source #
JWTCustomClaimsMapValueG
is used to represent a single value of
the JWTCustomClaimsMap
. A JWTCustomClaimsMapValueG
can either be
an JSON object or the literal value of the claim. If the value is an
JSON object, then it should contain a key path
, which is the JSON path
to the claim value in the JWT token. There's also an option to specify a
default value in the map via the 'default' key, which will be used
when a peek at the JWT token using the JSON path fails (key does not exist).
JWTCustomClaimsMapJSONPath !JSONPath !(Maybe v) | JSONPath to the key in the claims map, in case the key doesn't exist in the claims map then the default value will be used (if provided) |
JWTCustomClaimsMapStatic !v |
Instances
type CustomClaimsMap = HashMap SessionVariable JWTCustomClaimsMapValue Source #
data JWTCustomClaimsMap Source #
JWTClaimsMap is an option to provide a custom JWT claims map.
The JWTClaimsMap should be specified in the HASURA_GRAPHQL_JWT_SECRET
in the claims_map
. The JWTClaimsMap, if specified, requires two
mandatory fields, namely, `x-hasura-allowed-roles` and the
`x-hasura-default-role`, other claims may also be provided in the claims map.
Instances
Eq JWTCustomClaimsMap Source # | |
Defined in Hasura.Server.Auth.JWT (==) :: JWTCustomClaimsMap -> JWTCustomClaimsMap -> Bool # (/=) :: JWTCustomClaimsMap -> JWTCustomClaimsMap -> Bool # | |
Show JWTCustomClaimsMap Source # | |
Defined in Hasura.Server.Auth.JWT showsPrec :: Int -> JWTCustomClaimsMap -> ShowS # show :: JWTCustomClaimsMap -> String # showList :: [JWTCustomClaimsMap] -> ShowS # | |
FromJSON JWTCustomClaimsMap Source # | |
Defined in Hasura.Server.Auth.JWT parseJSON :: Value -> Parser JWTCustomClaimsMap parseJSONList :: Value -> Parser [JWTCustomClaimsMap] | |
ToJSON JWTCustomClaimsMap Source # | |
Defined in Hasura.Server.Auth.JWT toJSON :: JWTCustomClaimsMap -> Value toEncoding :: JWTCustomClaimsMap -> Encoding toJSONList :: [JWTCustomClaimsMap] -> Value toEncodingList :: [JWTCustomClaimsMap] -> Encoding |
data JWTNamespace Source #
JWTNamespace is used to locate the claims map within the JWT token. The location can be either provided via a JSON path or the name of the key in the JWT token.
ClaimNsPath JSONPath | |
ClaimNs Text |
Instances
Eq JWTNamespace Source # | |
Defined in Hasura.Server.Auth.JWT (==) :: JWTNamespace -> JWTNamespace -> Bool # (/=) :: JWTNamespace -> JWTNamespace -> Bool # | |
Show JWTNamespace Source # | |
Defined in Hasura.Server.Auth.JWT showsPrec :: Int -> JWTNamespace -> ShowS # show :: JWTNamespace -> String # showList :: [JWTNamespace] -> ShowS # | |
ToJSON JWTNamespace Source # | |
Defined in Hasura.Server.Auth.JWT toJSON :: JWTNamespace -> Value toEncoding :: JWTNamespace -> Encoding toJSONList :: [JWTNamespace] -> Value toEncodingList :: [JWTNamespace] -> Encoding |
Instances
newtype StringOrURI Source #
Hashable Wrapper for constructing a HashMap of JWTConfigs
StringOrURI | |
|
Instances
The JWT configuration we got from the user.
JWTConfig | |
|
Instances
Eq JWTConfig Source # | |
Show JWTConfig Source # | |
FromJSON JWTConfig Source # | Parse from a json string like: | `{"type": RS256, "key": "PEM-encoded-public-key-or-X509-cert"}` | to JWTConfig |
Defined in Hasura.Server.Auth.JWT parseJSON :: Value -> Parser JWTConfig parseJSONList :: Value -> Parser [JWTConfig] | |
ToJSON JWTConfig Source # | |
Defined in Hasura.Server.Auth.JWT toEncoding :: JWTConfig -> Encoding toJSONList :: [JWTConfig] -> Value toEncodingList :: [JWTConfig] -> Encoding | |
FromEnv JWTConfig Source # | |
FromEnv [JWTConfig] Source # | |
The validated runtime JWT configuration returned by mkJwtCtx
in setupAuthMode
.
This is also evidence that the jwkRefreshCtrl
thread is running, if an
expiration schedule could be determined.
JWTCtx | |
|
data HasuraClaims Source #
jwkRefreshCtrl :: (MonadIO m, MonadBaseControl IO m, HasReporter m) => Logger Hasura -> Manager -> URI -> IORef JWKSet -> DiffTime -> m void Source #
An action that refreshes the JWK at intervals in an infinite loop.
updateJwkRef :: (MonadIO m, MonadBaseControl IO m, MonadError JwkFetchError m, MonadTrace m) => Logger Hasura -> Manager -> URI -> IORef JWKSet -> m (Maybe NominalDiffTime) Source #
Given a JWK url, fetch JWK from it and update the IORef
determineJwkExpiryLifetime :: forall m. (MonadIO m, MonadError JwkFetchError m) => m UTCTime -> Logger Hasura -> ResponseHeaders -> m (Maybe NominalDiffTime) Source #
First check for Cache-Control header, if not found, look for Expires header
type ClaimsMap = HashMap SessionVariable Value Source #
decodeClaimsSet :: RawJWT -> Maybe ClaimsSet Source #
Decode a Jose ClaimsSet without verifying the signature
tokenIssuer :: RawJWT -> Maybe StringOrURI Source #
Extract the issuer from a bearer tokena _without_ verifying it.
processJwt :: (MonadIO m, MonadError QErr m) => [JWTCtx] -> RequestHeaders -> Maybe RoleName -> m (UserInfo, Maybe UTCTime, [Header]) Source #
Process the request headers to verify the JWT and extract UserInfo from it From the JWT config, we check which header to expect, it can be the Authorization or Cookie header
Iff no Authorization/Cookie header was passed, we will fall back to the unauthenticated user role [1], if one was configured at server start.
When no 'x-hasura-user-role' is specified in the request, the mandatory 'x-hasura-default-role' [2] from the JWT claims will be used.
type AuthTokenLocation = JWTHeader Source #
processHeaderSimple :: (MonadIO m, MonadError QErr m) => JWTCtx -> ByteString -> m (ClaimsMap, Maybe UTCTime) Source #
Processes a token payload (excluding the `Bearer ` prefix in the context of a JWTCtx)
:: MonadError QErr m | |
=> ClaimsSet | Unregistered JWT claims |
-> JWTClaims | Claims config |
-> m ClaimsMap | Hasura claims and other claims |
parse the claims map from the JWT token or custom claims from the JWT config
verifyJwt :: (MonadError JWTError m, MonadIO m) => JWTCtx -> RawJWT -> m ClaimsSet Source #
Verify the JWT against given JWK
parseHasuraClaims :: forall m. MonadError QErr m => ClaimsMap -> m HasuraClaims Source #
parseJwtClaim :: (FromJSON a, MonadError QErr m) => Value -> Text -> m a Source #