{"id":36967284,"url":"https://github.com/vapor/authentication","last_synced_at":"2026-01-13T20:01:26.310Z","repository":{"id":63921205,"uuid":"82072407","full_name":"vapor/authentication","owner":"vapor","description":"👤 Lightweight authentication framework for Swift","archived":false,"fork":false,"pushed_at":"2025-12-30T16:37:42.000Z","size":170,"stargazers_count":54,"open_issues_count":3,"forks_count":33,"subscribers_count":18,"default_branch":"main","last_synced_at":"2026-01-03T10:49:10.867Z","etag":null,"topics":["authentication","authorization","fluent","server-side-swift","swift-linux","vapor","vapor-service"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vapor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["vapor"],"open_collective":"vapor"}},"created_at":"2017-02-15T14:59:00.000Z","updated_at":"2025-12-30T16:15:07.000Z","dependencies_parsed_at":"2023-01-14T14:15:39.997Z","dependency_job_id":null,"html_url":"https://github.com/vapor/authentication","commit_stats":null,"previous_names":[],"tags_count":34,"template":false,"template_full_name":null,"purl":"pkg:github/vapor/authentication","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vapor%2Fauthentication","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vapor%2Fauthentication/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vapor%2Fauthentication/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vapor%2Fauthentication/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vapor","download_url":"https://codeload.github.com/vapor/authentication/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vapor%2Fauthentication/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28398792,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T14:36:09.778Z","status":"ssl_error","status_checked_at":"2026-01-13T14:35:19.697Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","authorization","fluent","server-side-swift","swift-linux","vapor","vapor-service"],"created_at":"2026-01-13T20:01:25.281Z","updated_at":"2026-01-13T20:01:26.302Z","avatar_url":"https://github.com/vapor.png","language":"C","funding_links":["https://github.com/sponsors/vapor","https://opencollective.com/vapor"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/1342803/36690387-2b24de90-1b00-11e8-8a8a-5cae6c96261b.png\" height=\"96\" alt=\"Vapor Authentication\"\u003e\n\u003cbr\u003e\n\u003cbr\u003e\n\u003ca href=\"https://docs.vapor.codes/4.0/\"\u003e\u003cimg src=\"https://design.vapor.codes/images/readthedocs.svg\" alt=\"Documentation\"\u003e\u003c/a\u003e\n\u003ca href=\"https://discord.gg/vapor\"\u003e\u003cimg src=\"https://design.vapor.codes/images/discordchat.svg\" alt=\"Team Chat\"\u003e\u003c/a\u003e\n\u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://design.vapor.codes/images/mitlicense.svg\" alt=\"MIT License\"\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/vapor/authentication/actions/workflows/test.yml\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/vapor/authentication/test.yml?event=push\u0026style=plastic\u0026logo=github\u0026label=tests\u0026logoColor=%23ccc\" alt=\"Continuous Integration\"\u003e\u003c/a\u003e\n\u003ca href=\"https://codecov.io/github/vapor/authentication\"\u003e\u003cimg src=\"https://img.shields.io/codecov/c/github/vapor/authentication?style=plastic\u0026logo=codecov\u0026label=codecov\" alt=\"Code Coverage\"\u003e\u003c/a\u003e\n\u003ca href=\"https://swift.org\"\u003e\u003cimg src=\"https://design.vapor.codes/images/swift62up.svg\" alt=\"Swift 6.2+\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nA lightweight authentication library for Swift providing common authentication operations, such as password hashing and OTP verification and generation.\n\n## Installation\n\nAdd the Authentication package to your `Package.swift` dependencies:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/vapor/authentication.git\", from: \"3.0.0\")\n]\n```\n\nThen add `Authentication` to your target's dependencies:\n\n```swift\ntargets: [\n    .target(\n        name: \"YourTarget\",\n        dependencies: [\n            .product(name: \"Authentication\", package: \"authentication\")\n        ]\n    )\n]\n```\n\n## Password Hashing\n\nSecurely hash and verify user passwords using the bcrypt algorithm, the `PasswordHasher` protocol or the PBKDF2 algorithm:\n\n```swift\nimport Authentication\n\n// Create a hasher with default cost (12)\nlet hasher = BcryptHasher()\n// Or use PBKDF2\nlet hasher = PBKDF2Hasher()\n// Or a hasher injected in\nlet hasher: PasswordHasher\n\n// Hash a password\nlet hash = try hasher.hash(\"secretPassword123\")\n\n// Verify a password against a hash\nlet isValid = try hasher.verify(\"secretPassword123\", created: hash)\n// isValid == true\n```\n\n### Configuration\n\n#### Bcrypt\n\nThe cost parameter controls how computationally expensive the hashing operation is. Higher costs provide more security but take longer to compute:\n\n```swift\n// Create a bcrypt hasher with custom cost (valid range: 4-31)\nlet hasher = BcryptHasher(cost: 14)\n\nlet hash = try hasher.hash(\"myPassword\")\n```\n\n\u003e **Note**: Increasing the cost by 1 doubles the computation time. A cost of 12 takes approximately 250ms on modern hardware.\n\n#### PBKDF2\n\nIn PBKDF2 you can configure the number of iterations and hashing function. There are sensible standards in place already depending on the hash algorithm used, so only adjust the iterations if necessary:\n\n```swift\n// Create a PBKDF2 hasher with custom iterations\nlet hasher = PBKDF2Hasher(\n    pseudoRandomFunction: .sha256,\n    iterations: 600_000,\n)\nlet hash = try hasher.hash(\"myPassword\")\n```\n\n\n## One-Time Passwords (OTP)\n\nGenerate RFC-compliant HOTP and TOTP codes for multi-factor authentication.\n\n### Time-Based One-Time Passwords (TOTP)\n\nTOTP generates codes that change at regular intervals (typically 30 seconds):\n\n```swift\nimport Authentication\nimport Crypto\n\n// Create a symmetric key (store this securely per user)\nlet key = SymmetricKey(size: .bits256)\n\n// Create a TOTP generator\nlet totp = TOTP(key: key, digest: .sha256)\n\n// Generate a code for the current time\nlet code = totp.generate(time: Date())\nprint(code)  // e.g., \"482719\"\n```\n\n### Hash-Based One-Time Passwords (HOTP)\n\nHOTP generates codes based on a counter value:\n\n```swift\nimport Authentication\nimport Crypto\n\nlet key = SymmetricKey(size: .bits256)\n\n// Create an HOTP generator\nlet hotp = HOTP(key: key, digest: .sha256)\n\n// Generate codes for sequential counters\nlet code0 = hotp.generate(counter: 0)\nlet code1 = hotp.generate(counter: 1)\n```\n\n### Configuring OTP Parameters\n\nBoth HOTP and TOTP support configuration options:\n\n```swift\n// Configure digest algorithm: .sha1, .sha256, or .sha512\nlet totp = TOTP(key: key, digest: .sha512)\n\n// Configure code length: .six, .seven, or .eight digits\nlet totp = TOTP(key: key, digest: .sha256, digits: .eight)\n\n// Configure time interval (TOTP only, default: 30 seconds)\nlet totp = TOTP(key: key, digest: .sha256, interval: 60)\n```\n\n### Verifying Codes with Range Tolerance\n\nTo account for clock drift or user delays, generate multiple codes within a range:\n\n```swift\nlet totp = TOTP(key: key, digest: .sha256)\n\n// Generate codes for current time plus/minus 1 interval\nlet codes = totp.generate(time: Date(), range: 1)\n// Returns 3 codes: [previous, current, next]\n\n// Check if user's code matches any valid code\nlet isValid = codes.contains(userCode)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvapor%2Fauthentication","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvapor%2Fauthentication","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvapor%2Fauthentication/lists"}