diff --git a/Sources/OAuthKit/Extensions/URL+Extensions.swift b/Sources/OAuthKit/Extensions/URL+Extensions.swift index b5150c6..8db00b8 100644 --- a/Sources/OAuthKit/Extensions/URL+Extensions.swift +++ b/Sources/OAuthKit/Extensions/URL+Extensions.swift @@ -15,7 +15,7 @@ extension URL { absoluteString.sha256 } - /// Returns the SHA-256 Digest for this URL. + /// Returns the SHA-512 Digest for this URL. var sha512: SHA512.Digest { absoluteString.sha512 } diff --git a/Sources/OAuthKit/Keychain/Keychain.swift b/Sources/OAuthKit/Keychain/Keychain.swift index 2b78f1e..f78ce4f 100644 --- a/Sources/OAuthKit/Keychain/Keychain.swift +++ b/Sources/OAuthKit/Keychain/Keychain.swift @@ -47,7 +47,6 @@ class Keychain: @unchecked Sendable { guard status == noErr else { return [] } var results = [String]() - if let items = result as? [[String: Any]] { for item in items { if let key = item[kSecAttrAccount as String] as? String { diff --git a/Sources/OAuthKit/OAuth+DeviceCode.swift b/Sources/OAuthKit/OAuth+DeviceCode.swift index 8a6f3a9..40ce9f8 100644 --- a/Sources/OAuthKit/OAuth+DeviceCode.swift +++ b/Sources/OAuthKit/OAuth+DeviceCode.swift @@ -9,7 +9,7 @@ import Foundation extension OAuth { - /// A codable type that holds device code information. + /// A codable type returned from a server that holds device code information. /// - SeeAlso: /// [Requesting a Device Code](https://www.oauth.com/playground/device-code.html) public struct DeviceCode: Codable, Equatable, Sendable { diff --git a/Sources/OAuthKit/OAuth+GrantType.swift b/Sources/OAuthKit/OAuth+GrantType.swift index 9463ee8..2abb319 100644 --- a/Sources/OAuthKit/OAuth+GrantType.swift +++ b/Sources/OAuthKit/OAuth+GrantType.swift @@ -10,32 +10,30 @@ import Foundation extension OAuth { /// Provides an enum representation for the OAuth 2.0 Grant Types. - /// - /// See: https://oauth.net/2/grant-types/ public enum GrantType: Equatable, Sendable { /// The OAuth 2.0 authorization code workflow. - /// See: https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.1 + /// See RFC 6749 Standard [OAuth 2.0 Authorization Code Grant Type](https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.1) /// - Parameters: /// - String: the state verification string used to prevent CSRF attacks case authorizationCode(String) /// The OAuth 2.0 client credentials grant. - /// See: https://datatracker.ietf.org/doc/html/rfc6749#section-4.4 + /// See RFC 6749 Standard [OAuth 2.0 Client Credentials Code Grant Type](https://datatracker.ietf.org/doc/html/rfc6749#section-4.4) case clientCredentials /// The OAuth 2.0 device authorization grant. - /// See: https://datatracker.ietf.org/doc/html/rfc8628#section-3.4 + /// See RFC 6749 Standard [OAuth 2.0 Device Code Grant Type](https://datatracker.ietf.org/doc/html/rfc8628#section-3.4) case deviceCode /// The OAuth 2.0 Proof Key for Code Exchange is an extension to the Authorization Code - /// flow to prevent CSRF and authorization code injection attacks. + /// flow to prevent CSRF and authorization code injection attacks. See RFC 7636 Standard [OAuth 2.0 Proof Key for Code Exchange](https://datatracker.ietf.org/doc/html/rfc7636) /// - Parameters: /// - PKCE: the PKCE data case pkce(PKCE) /// The OAuth 2.0 Refresh Token grant type is used by clients to exchange a refresh token for an access token when the access token has expired. - /// See: https://datatracker.ietf.org/doc/html/rfc6749#section-1.5 + /// See RFC 6749 Standard [OAuth 2.0 Refresh Token](https://datatracker.ietf.org/doc/html/rfc6749#section-1.5) case refreshToken /// The raw string value for a grant type. diff --git a/Sources/OAuthKit/OAuth+PKCE.swift b/Sources/OAuthKit/OAuth+PKCE.swift index 302a399..4dafd8d 100644 --- a/Sources/OAuthKit/OAuth+PKCE.swift +++ b/Sources/OAuthKit/OAuth+PKCE.swift @@ -12,23 +12,22 @@ private let defaultCodeChallengeMethod = "S256" extension OAuth { - /// Provides a structure for OAuth 2.0 Authorization Code Flow with Proof Key for Code Exchange (PKCE) + /// Provides a structure for OAuth 2.0 Authorization Code Flow with Proof Key for Code Exchange (PKCE). public struct PKCE: Equatable, Sendable { - /// A cryptographically random string using the characters A-Z, a-z, 0-9, and the punctuation characters - - /// ._~ (hyphen, period, underscore, and tilde), between 43 and 128 characters long. - /// See: https://datatracker.ietf.org/doc/html/rfc7636#section-4.1 - let codeVerifier: String + /// A cryptographically random string between 43 and 128 characters long. + /// See RFC 7636 Standard [PKCE Code Verifier](https://datatracker.ietf.org/doc/html/rfc7636#section-4.1). + public let codeVerifier: String - /// A transformation of the codeVerifier that is SHA-256 hashed and Base 64 URL encoded. - /// See: https://datatracker.ietf.org/doc/html/rfc7636#section-4.2 - let codeChallenge: String + /// A code challenge derived from the codeVerifier that is a Base 64 URL encoded string from it's SHA-256 digest. + /// See RFC 7636 Standard [PKCE Code Challenge](https://datatracker.ietf.org/doc/html/rfc7636#section-4.2). + public let codeChallenge: String /// The PKCE state code. - let state: String + public let state: String - /// Returns the code challenge method. - var codeChallengeMethod: String { + /// Returns the code challenge method. Currently only supports [SHA-256 hash](https://en.wikipedia.org/wiki/SHA-2). + public var codeChallengeMethod: String { defaultCodeChallengeMethod } diff --git a/Sources/OAuthKit/OAuth+Provider.swift b/Sources/OAuthKit/OAuth+Provider.swift index 6e83e4f..c8c3cc1 100644 --- a/Sources/OAuthKit/OAuth+Provider.swift +++ b/Sources/OAuthKit/OAuth+Provider.swift @@ -9,7 +9,7 @@ import Foundation extension OAuth { - /// Provides configuration data for an OAuth service provider. + /// Provides configuration data for an OAuth 2.0 service provider. public struct Provider: Codable, Identifiable, Hashable, Sendable { /// The provider unique id. diff --git a/Sources/OAuthKit/OAuthKit.docc/Extensions/GrantType.md b/Sources/OAuthKit/OAuthKit.docc/Extensions/GrantType.md new file mode 100644 index 0000000..e850044 --- /dev/null +++ b/Sources/OAuthKit/OAuthKit.docc/Extensions/GrantType.md @@ -0,0 +1,30 @@ +# ``OAuthKit/OAuth/GrantType`` + +@Metadata { + @Available(iOS, introduced: "18.0") + @Available(macOS, introduced: "15.0") + @Available(tvOS, introduced: "18.0") + @Available(visionOS, introduced: "2.0") + @Available(watchOS, introduced: "11.0") +} + +## Overview +A GrantType is used to define how an application obtains an access token from an OAuth 2.0 server. OAuthKit supports all major OAuth 2.0 grant types: +- [Authorization Code](``authorizationCode(_:)``) +- [Client Credentials](``clientCredentials``) +- [Device Code](``deviceCode``) +- [Proof Key for Code Exchange (PKCE)](``pkce(_:)``) +- [Refresh Token](``refreshToken``) + + +> Important: For apps that don't have access to a web browser (like tvOS or watchOS), you'll need to start +an ``OAuth/authorize(provider:grantType:)`` flow with the ``deviceCode`` grant Type. See for more details. + +> Tip: The [OAuth 2.0 Playground](https://www.oauth.com/playground/index.html) will help you understand the OAuth authorization flows and show each step of the process of obtaining an access token. + +## Topics + +### Associated Values + +- ``OAuth/PKCE`` +- ``OAuth/DeviceCode`` diff --git a/Sources/OAuthKit/OAuthKit.docc/Extensions/OAuth.md b/Sources/OAuthKit/OAuthKit.docc/Extensions/OAuth.md index 8ee463d..055b047 100644 --- a/Sources/OAuthKit/OAuthKit.docc/Extensions/OAuth.md +++ b/Sources/OAuthKit/OAuthKit.docc/Extensions/OAuth.md @@ -1,4 +1,11 @@ # ``OAuthKit/OAuth`` +@Metadata { + @Available(iOS, introduced: "18.0") + @Available(macOS, introduced: "15.0") + @Available(tvOS, introduced: "18.0") + @Available(visionOS, introduced: "2.0") + @Available(watchOS, introduced: "11.0") +} ## Topics @@ -10,6 +17,7 @@ ### Starting an authorization flow - ``authorize(provider:grantType:)`` +- ``OAuth/GrantType`` ### OAuth State Tracking diff --git a/Sources/OAuthKit/OAuthKit.docc/Extensions/Provider.md b/Sources/OAuthKit/OAuthKit.docc/Extensions/Provider.md new file mode 100644 index 0000000..0a7153b --- /dev/null +++ b/Sources/OAuthKit/OAuthKit.docc/Extensions/Provider.md @@ -0,0 +1,32 @@ +# ``OAuthKit/OAuth/Provider`` + +@Metadata { + @Available(iOS, introduced: "18.0") + @Available(macOS, introduced: "15.0") + @Available(tvOS, introduced: "18.0") + @Available(visionOS, introduced: "2.0") + @Available(watchOS, introduced: "11.0") +} + +## Overview +The Provider holds the configuration data that is used for communicating with an OAuth 2.0 server. The easiest way to configure OAuthKit is to simply drop an `oauth.json` file into your main bundle and it will get automatically loaded into your swift application and available as an ``SwiftUICore/EnvironmentValues/oauth`` property wrapper. You can find an example `oauth.json` file [here](https://github.com/codefiesta/OAuthKit/blob/main/Tests/OAuthKitTests/Resources/oauth.json). +```json +[ + { + "id": "GitHub", + "authorizationURL": "https://github.com/login/oauth/authorize", + "accessTokenURL": "https://github.com/login/oauth/access_token", + "deviceCodeURL": "https://github.com/login/device/code", + "clientID": "CLIENT_ID", + "clientSecret": "CLIENT_SECRET", + "redirectURI": "oauthkit://callback", + "scope": [ + "user", + "repo", + "openid" + ], + "debug": true + } +] +``` +> Warning: It's highly recommended that developers only use `oauth.json` files during development and don't include them in publicly distributed applications. It is possible for someone to [inspect and reverse engineer](https://www.nowsecure.com/blog/2021/09/08/basics-of-reverse-engineering-ios-mobile-apps/) the contents of your app and look at any files inside your app bundle which means you could potentially expose any confidential values contained in this file. It's recommended to build OAuth Providers Programmatically via your CI Build Pipeline. Most continuous integration and delivery platforms have the ability to generate source code during build workflows that can get compiled into Swift byte code. It's should be feasible to write a step in the CI pipeline that generates a .swift file that provides access to a list of OAuth.Provider objects that have their confidential values set from the secure CI platform secret keys. This swift code can then compiled into the application as byte code. In practical terms, the security and obfuscation inherent in compiled languages make extracting confidential values difficult (but not impossible). diff --git a/Sources/OAuthKit/OAuthKit.docc/OAuthKit.md b/Sources/OAuthKit/OAuthKit.docc/OAuthKit.md index cba9fc8..36a5547 100644 --- a/Sources/OAuthKit/OAuthKit.docc/OAuthKit.md +++ b/Sources/OAuthKit/OAuthKit.docc/OAuthKit.md @@ -37,6 +37,8 @@ This has the advantage of avoiding direct coupling with an authorization flow, e - - - ``OAuth`` +- ``OAuth/Provider`` +- ``OAuth/GrantType`` ### State Observability - ``OAuth/state``