Skip to content

Commit

Permalink
Merge pull request #50 from soto-project/jwt-kit-5
Browse files Browse the repository at this point in the history
Use jwt-kit v5 beta
  • Loading branch information
adam-fowler authored Jul 1, 2024
2 parents cc1c298 + edb6d20 commit 48a9eea
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 45 deletions.
37 changes: 18 additions & 19 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,30 @@ env:
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

jobs:
macOS:
runs-on: macOS-13
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Test
run: swift test --enable-code-coverage
- name: Convert coverage files
run: |
xcrun llvm-cov export -format="lcov" \
.build/debug/soto-cognito-authentication-kitPackageTests.xctest/Contents/MacOs/soto-cognito-authentication-kitPackageTests \
-ignore-filename-regex="(\/\.build\/|\/Tests\/)" \
-instr-profile .build/debug/codecov/default.profdata > info.lcov
- name: Upload to codecov.io
uses: codecov/codecov-action@v1
with:
file: info.lcov
# macOS:
# runs-on: macOS-13
# steps:
# - name: Checkout
# uses: actions/checkout@v3
# - name: Test
# run: swift test --enable-code-coverage
# - name: Convert coverage files
# run: |
# xcrun llvm-cov export -format="lcov" \
# .build/debug/soto-cognito-authentication-kitPackageTests.xctest/Contents/MacOs/soto-cognito-authentication-kitPackageTests \
# -ignore-filename-regex="(\/\.build\/|\/Tests\/)" \
# -instr-profile .build/debug/codecov/default.profdata > info.lcov
# - name: Upload to codecov.io
# uses: codecov/codecov-action@v1
# with:
# file: info.lcov

linux:
strategy:
matrix:
image:
- swift:5.8
- swift:5.9
- swift:5.10
- swiftlang/swift:nightly-6.0-jammy
runs-on: ubuntu-latest
container:
image: ${{ matrix.image }}
Expand Down
12 changes: 6 additions & 6 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version:5.8
// swift-tools-version:5.10
//===----------------------------------------------------------------------===//
//
// This source file is part of the Soto for AWS open source project
Expand All @@ -24,19 +24,19 @@ let swiftSettings: [SwiftSetting] = [
let package = Package(
name: "soto-cognito-authentication-kit",
platforms: [
.macOS(.v10_15),
.iOS(.v13),
.tvOS(.v13),
.macOS(.v13),
.iOS(.v16),
.tvOS(.v16),
],
products: [
.library(name: "SotoCognitoAuthenticationKit", targets: ["SotoCognitoAuthenticationKit"]),
.library(name: "SotoCognitoAuthenticationSRP", targets: ["SotoCognitoAuthenticationSRP"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-crypto.git", "1.0.0"..<"4.0.0"),
.package(url: "https://github.com/soto-project/soto.git", from: "7.0.0-beta"),
.package(url: "https://github.com/soto-project/soto.git", from: "7.0.0-rc.1"),
.package(url: "https://github.com/swift-server/async-http-client.git", from: "1.10.0"),
.package(url: "https://github.com/vapor/jwt-kit.git", .upToNextMajor(from: "4.2.6")),
.package(url: "https://github.com/vapor/jwt-kit.git", from: "5.0.0-beta.4"),
// for SRP
.package(url: "https://github.com/adam-fowler/big-num.git", .upToNextMajor(from: "2.0.0")),
],
Expand Down
12 changes: 6 additions & 6 deletions Sources/SotoCognitoAuthenticationKit/Authenticatable+JWT.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ public extension CognitoAuthenticatable {
/// - on: Event loop to run on
/// - returns:
/// Payload structure.
func authenticate<Payload: Codable>(
func authenticate<Payload: Codable & Sendable>(
idToken: String,
logger: Logger = AWSClient.loggingDisabled
) async throws -> Payload {
let signers = try await loadSigners(region: configuration.region, logger: logger)
let jwtPayload = try signers.verify(idToken, as: VerifiedToken<IdTokenVerifier, Payload>.self)
let jwtPayload = try await signers.verify(idToken, as: VerifiedToken<IdTokenVerifier, Payload>.self)
guard jwtPayload.token.audience == self.configuration.clientId else { throw SotoCognitoError.unauthorized(reason: "invalid token") }
guard jwtPayload.token.issuer == "https://cognito-idp.\(self.configuration.region.rawValue).amazonaws.com/\(self.configuration.userPoolId)" else {
throw SotoCognitoError.unauthorized(reason: "invalid token")
Expand All @@ -71,7 +71,7 @@ public extension CognitoAuthenticatable {
logger: Logger = AWSClient.loggingDisabled
) async throws -> CognitoAccessToken {
let signers = try await loadSigners(region: configuration.region, logger: logger)
let jwtPayload = try signers.verify(accessToken, as: VerifiedToken<AccessTokenVerifier, CognitoAccessToken>.self)
let jwtPayload = try await signers.verify(accessToken, as: VerifiedToken<AccessTokenVerifier, CognitoAccessToken>.self)
guard jwtPayload.token.issuer == "https://cognito-idp.\(self.configuration.region.rawValue).amazonaws.com/\(self.configuration.userPoolId)" else {
throw SotoCognitoError.unauthorized(reason: "invalid token")
}
Expand All @@ -84,7 +84,7 @@ extension CognitoAuthenticatable {
func loadSigners(
region: Region,
logger: Logger = AWSClient.loggingDisabled
) async throws -> JWTSigners {
) async throws -> JWTKeyCollection {
// check we haven't already loaded the jwt signing key set
if let jwtSigners = self.jwtSigners {
return jwtSigners
Expand All @@ -99,9 +99,9 @@ extension CognitoAuthenticatable {
timeout: .seconds(20),
logger: logger
)
let signers = JWTSigners()
let signers = JWTKeyCollection()
let data = try await response.body.collect(upTo: 1_000_000)
try signers.use(jwksJSON: String(buffer: data))
try await signers.use(jwksJSON: String(buffer: data))
self.jwtSigners = signers
return signers
}
Expand Down
11 changes: 2 additions & 9 deletions Sources/SotoCognitoAuthenticationKit/Authenticatable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -101,22 +101,15 @@ public final class CognitoAuthenticatable {
/// Configuration
public let configuration: CognitoConfiguration
/// JWT Signers
var jwtSigners: JWTSigners? {
get { self.jwtSignersLock.withLock { self._jwtSigners }}
set { self.jwtSignersLock.withLock { self._jwtSigners = newValue }}
}

private var _jwtSigners: JWTSigners?
private let jwtSignersLock: NIOLock
var jwtSigners: JWTKeyCollection?

// MARK: Initialization

/// Initialize `CognitoAuthenticatable`
/// - Parameter configuration: cognito authentication configuration
public init(configuration: CognitoConfiguration) {
self.configuration = configuration
self._jwtSigners = nil
self.jwtSignersLock = .init()
self.jwtSigners = nil
}

// MARK: Methods
Expand Down
11 changes: 6 additions & 5 deletions Sources/SotoCognitoAuthenticationKit/Tokens.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//

import Foundation
import JWTKit

/// JWT Access token
Expand All @@ -20,7 +21,7 @@ struct AccessTokenVerifier: JWTPayload {
let issuer: String
let tokenUse: String

func verify(using signer: JWTSigner) throws {
func verify(using algorithm: some JWTAlgorithm) async throws {
guard self.expirationTime > Date() else { throw SotoCognitoError.unauthorized(reason: "token expired") }
guard self.tokenUse == "access" else { throw SotoCognitoError.unauthorized(reason: "invalid token") }
}
Expand All @@ -39,7 +40,7 @@ struct IdTokenVerifier: JWTPayload {
let issuer: String
let tokenUse: String

func verify(using signer: JWTSigner) throws {
func verify(using algorithm: some JWTAlgorithm) async throws {
guard self.expirationTime > Date() else { throw SotoCognitoError.unauthorized(reason: "token expired") }
guard self.tokenUse == "id" else { throw SotoCognitoError.unauthorized(reason: "invalid token") }
}
Expand All @@ -53,7 +54,7 @@ struct IdTokenVerifier: JWTPayload {
}

/// JWT payload that encapsulates both a verified token and an output payload
struct VerifiedToken<Token: JWTPayload, Payload: Codable>: JWTPayload {
struct VerifiedToken<Token: JWTPayload, Payload: Codable & Sendable>: JWTPayload {
let token: Token
let payload: Payload

Expand All @@ -62,7 +63,7 @@ struct VerifiedToken<Token: JWTPayload, Payload: Codable>: JWTPayload {
self.payload = try Payload(from: decoder)
}

func verify(using signer: JWTSigner) throws {
try self.token.verify(using: signer)
func verify(using algorithm: some JWTAlgorithm) async throws {
try await self.token.verify(using: algorithm)
}
}

0 comments on commit 48a9eea

Please sign in to comment.