Merge pull request #1580 from haskell-servant/jkarni/servant-auth-io-keyset

Allow IO in JWTSettings' validationKeys
This commit is contained in:
Julian Arni 2022-04-23 18:17:00 -03:00 committed by GitHub
commit 5e1569e9e2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 18 additions and 5 deletions

12
changelog.d/1580 Normal file
View file

@ -0,0 +1,12 @@
synopsis: Allow IO in validationKeys
prs: #1580
issues: #1579
description: {
Currently validationKeys are a fixed JWKSet. This does not work with OIDC
providers such as AWS Cognito or Okta, which regularly fetching jwks_uri to
discover new and expired keys.
This change alters the type of validationKeys from JWKSet to IO JWKSet.
}

View file

@ -33,7 +33,7 @@ data JWTSettings = JWTSettings
-- | Algorithm used to sign JWT. -- | Algorithm used to sign JWT.
, jwtAlg :: Maybe Jose.Alg , jwtAlg :: Maybe Jose.Alg
-- | Keys used to validate JWT. -- | Keys used to validate JWT.
, validationKeys :: Jose.JWKSet , validationKeys :: IO Jose.JWKSet
-- | An @aud@ predicate. The @aud@ is a string or URI that identifies the -- | An @aud@ predicate. The @aud@ is a string or URI that identifies the
-- intended recipient of the JWT. -- intended recipient of the JWT.
, audienceMatches :: Jose.StringOrURI -> IsMatch , audienceMatches :: Jose.StringOrURI -> IsMatch
@ -44,7 +44,7 @@ defaultJWTSettings :: Jose.JWK -> JWTSettings
defaultJWTSettings k = JWTSettings defaultJWTSettings k = JWTSettings
{ signingKey = k { signingKey = k
, jwtAlg = Nothing , jwtAlg = Nothing
, validationKeys = Jose.JWKSet [k] , validationKeys = pure $ Jose.JWKSet [k]
, audienceMatches = const Matches } , audienceMatches = const Matches }
-- | The policies to use when generating cookies. -- | The policies to use when generating cookies.

View file

@ -58,11 +58,12 @@ makeJWT v cfg expiry = runExceptT $ do
verifyJWT :: FromJWT a => JWTSettings -> BS.ByteString -> IO (Maybe a) verifyJWT :: FromJWT a => JWTSettings -> BS.ByteString -> IO (Maybe a)
verifyJWT jwtCfg input = do verifyJWT jwtCfg input = do
verifiedJWT <- liftIO $ runExceptT $ do keys <- validationKeys jwtCfg
verifiedJWT <- runExceptT $ do
unverifiedJWT <- Jose.decodeCompact (BSL.fromStrict input) unverifiedJWT <- Jose.decodeCompact (BSL.fromStrict input)
Jose.verifyClaims Jose.verifyClaims
(jwtSettingsToJwtValidationSettings jwtCfg) (jwtSettingsToJwtValidationSettings jwtCfg)
(validationKeys jwtCfg) keys
unverifiedJWT unverifiedJWT
return $ case verifiedJWT of return $ case verifiedJWT of
Left (_ :: Jose.JWTError) -> Nothing Left (_ :: Jose.JWTError) -> Nothing