diff --git a/OAuth2.xcodeproj/project.pbxproj b/OAuth2.xcodeproj/project.pbxproj index f5e5f45..a9fc424 100644 --- a/OAuth2.xcodeproj/project.pbxproj +++ b/OAuth2.xcodeproj/project.pbxproj @@ -33,6 +33,15 @@ 8793811929D483EC00DC4EBC /* OAuth2DeviceGrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8793811829D483EC00DC4EBC /* OAuth2DeviceGrant.swift */; }; 8793811A29D483EC00DC4EBC /* OAuth2DeviceGrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8793811829D483EC00DC4EBC /* OAuth2DeviceGrant.swift */; }; 8793811B29D483EC00DC4EBC /* OAuth2DeviceGrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8793811829D483EC00DC4EBC /* OAuth2DeviceGrant.swift */; }; + 879EE6F02CF61295008B3D74 /* OAuth2ResponseTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 879EE6ED2CF61295008B3D74 /* OAuth2ResponseTypes.swift */; }; + 879EE6F12CF61295008B3D74 /* OAuth2TokenTypeIdentifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 879EE6EE2CF61295008B3D74 /* OAuth2TokenTypeIdentifiers.swift */; }; + 879EE6F22CF61295008B3D74 /* OAuth2GrantTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 879EE6EC2CF61295008B3D74 /* OAuth2GrantTypes.swift */; }; + 879EE6F32CF61295008B3D74 /* OAuth2ResponseTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 879EE6ED2CF61295008B3D74 /* OAuth2ResponseTypes.swift */; }; + 879EE6F42CF61295008B3D74 /* OAuth2TokenTypeIdentifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 879EE6EE2CF61295008B3D74 /* OAuth2TokenTypeIdentifiers.swift */; }; + 879EE6F52CF61295008B3D74 /* OAuth2GrantTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 879EE6EC2CF61295008B3D74 /* OAuth2GrantTypes.swift */; }; + 879EE6F62CF61295008B3D74 /* OAuth2ResponseTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 879EE6ED2CF61295008B3D74 /* OAuth2ResponseTypes.swift */; }; + 879EE6F72CF61295008B3D74 /* OAuth2TokenTypeIdentifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 879EE6EE2CF61295008B3D74 /* OAuth2TokenTypeIdentifiers.swift */; }; + 879EE6F82CF61295008B3D74 /* OAuth2GrantTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 879EE6EC2CF61295008B3D74 /* OAuth2GrantTypes.swift */; }; 87B3E07C29F6AF240075C4DC /* OAuth2DeviceGrantTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87B3E07B29F6AF240075C4DC /* OAuth2DeviceGrantTests.swift */; }; CCCE40D6B4EAD9BF05C92ACE /* OAuth2CustomAuthorizer+iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = CCCE4C8DC3CB7713E59BC1EE /* OAuth2CustomAuthorizer+iOS.swift */; }; DD0CCBAD1C4DC83A0044C4E3 /* OAuth2WebViewController+macOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD0CCBAC1C4DC83A0044C4E3 /* OAuth2WebViewController+macOS.swift */; }; @@ -174,6 +183,9 @@ 659854461C5B3BEA00237D39 /* OAuth2.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OAuth2.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 65EC05DF1C9050CB00DE9186 /* OAuth2KeychainAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OAuth2KeychainAccount.swift; sourceTree = ""; }; 8793811829D483EC00DC4EBC /* OAuth2DeviceGrant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuth2DeviceGrant.swift; sourceTree = ""; }; + 879EE6EC2CF61295008B3D74 /* OAuth2GrantTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuth2GrantTypes.swift; sourceTree = ""; }; + 879EE6ED2CF61295008B3D74 /* OAuth2ResponseTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuth2ResponseTypes.swift; sourceTree = ""; }; + 879EE6EE2CF61295008B3D74 /* OAuth2TokenTypeIdentifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuth2TokenTypeIdentifiers.swift; sourceTree = ""; }; 87B3E07B29F6AF240075C4DC /* OAuth2DeviceGrantTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OAuth2DeviceGrantTests.swift; sourceTree = ""; }; CCCE4C8DC3CB7713E59BC1EE /* OAuth2CustomAuthorizer+iOS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OAuth2CustomAuthorizer+iOS.swift"; sourceTree = ""; }; DD0CCBAC1C4DC83A0044C4E3 /* OAuth2WebViewController+macOS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "OAuth2WebViewController+macOS.swift"; sourceTree = ""; }; @@ -274,6 +286,16 @@ path = tvOS; sourceTree = ""; }; + 879EE6EF2CF61295008B3D74 /* Constants */ = { + isa = PBXGroup; + children = ( + 879EE6EC2CF61295008B3D74 /* OAuth2GrantTypes.swift */, + 879EE6ED2CF61295008B3D74 /* OAuth2ResponseTypes.swift */, + 879EE6EE2CF61295008B3D74 /* OAuth2TokenTypeIdentifiers.swift */, + ); + path = Constants; + sourceTree = ""; + }; EE2486281AC85DD4002B31AF /* iOS */ = { isa = PBXGroup; children = ( @@ -421,6 +443,7 @@ isa = PBXGroup; children = ( EE2983731D40BC8900933CDD /* Base */, + 879EE6EF2CF61295008B3D74 /* Constants */, EE79F65C1BFBDFFF00746243 /* Flows */, EE9EBF111D775A21003263FC /* DataLoader */, EE2486281AC85DD4002B31AF /* iOS */, @@ -662,6 +685,9 @@ 659854501C5B3C9C00237D39 /* OAuth2Requestable.swift in Sources */, 6598544F1C5B3C9C00237D39 /* OAuth2Base.swift in Sources */, 8793811B29D483EC00DC4EBC /* OAuth2DeviceGrant.swift in Sources */, + 879EE6F62CF61295008B3D74 /* OAuth2ResponseTypes.swift in Sources */, + 879EE6F72CF61295008B3D74 /* OAuth2TokenTypeIdentifiers.swift in Sources */, + 879EE6F82CF61295008B3D74 /* OAuth2GrantTypes.swift in Sources */, EEB9A97E1D86C34E0022EF66 /* OAuth2Response.swift in Sources */, EEFD23531C9ED9E400727DCF /* OAuth2ClientCredentialsReddit.swift in Sources */, 6598545A1C5B3CA700237D39 /* OAuth2PasswordGrant.swift in Sources */, @@ -705,6 +731,9 @@ EEC6D57D1C2837EA00FA9B1C /* OAuth2CodeGrantLinkedIn.swift in Sources */, EE79F6551BFA93D900746243 /* OAuth2AuthConfig.swift in Sources */, EEACE1D51A7E8DE8009BF3A7 /* OAuth2Base.swift in Sources */, + 879EE6F02CF61295008B3D74 /* OAuth2ResponseTypes.swift in Sources */, + 879EE6F12CF61295008B3D74 /* OAuth2TokenTypeIdentifiers.swift in Sources */, + 879EE6F22CF61295008B3D74 /* OAuth2GrantTypes.swift in Sources */, EEC7A8C91AE47111008C30E7 /* OAuth2Authorizer+iOS.swift in Sources */, EE1070351E5C7A4200250586 /* OAuth2CustomAuthorizerUI.swift in Sources */, EE2983761D40BE7600933CDD /* OAuth2AuthorizerUI.swift in Sources */, @@ -743,6 +772,9 @@ EE79F65A1BFAA36900746243 /* OAuth2Error.swift in Sources */, EEC49F311C9BF22400989A18 /* OAuth2AuthRequest.swift in Sources */, 8793811929D483EC00DC4EBC /* OAuth2DeviceGrant.swift in Sources */, + 879EE6F32CF61295008B3D74 /* OAuth2ResponseTypes.swift in Sources */, + 879EE6F42CF61295008B3D74 /* OAuth2TokenTypeIdentifiers.swift in Sources */, + 879EE6F52CF61295008B3D74 /* OAuth2GrantTypes.swift in Sources */, EE79F6571BFA945C00746243 /* OAuth2ClientConfig.swift in Sources */, 19C919DD1E51CC8000BFC834 /* OAuth2CustomAuthorizer+macOS.swift in Sources */, EE79F6541BFA93D900746243 /* OAuth2AuthConfig.swift in Sources */, diff --git a/Package.swift b/Package.swift index dbeb782..20d42f8 100644 --- a/Package.swift +++ b/Package.swift @@ -41,8 +41,9 @@ let package = Package( .target(name: "macOS", dependencies: [.target(name: "Base")]), .target(name: "iOS", dependencies: [.target(name: "Base")]), .target(name: "tvOS", dependencies: [.target(name: "Base")]), + .target(name: "Constants"), .target(name: "Flows", dependencies: [ - .target(name: "macOS"), .target(name: "iOS"), .target(name: "tvOS")]), + .target(name: "macOS"), .target(name: "iOS"), .target(name: "tvOS"), .target(name: "Constants")]), .target(name: "DataLoader", dependencies: [.target(name: "Flows")]), .testTarget(name: "BaseTests", dependencies: [.target(name: "Base"), .target(name: "Flows")]), .testTarget(name: "FlowTests", dependencies: [.target(name: "Flows")]), diff --git a/Sources/Constants/OAuth2GrantTypes.swift b/Sources/Constants/OAuth2GrantTypes.swift new file mode 100644 index 0000000..7bfed57 --- /dev/null +++ b/Sources/Constants/OAuth2GrantTypes.swift @@ -0,0 +1,12 @@ +public enum OAuth2GrantTypes { + public static let password = "password" + public static let authorizationCode = "authorization_code" + public static let clientCredentials = "client_credentials" + public static let refreshToken = "refresh_token" + public static let implicit = "implicit" + public static let saml2Bearer = "urn:ietf:params:oauth:grant-type:saml2-bearer" + public static let jwtBearer = "urn:ietf:params:oauth:grant-type:jwt-bearer" + public static let deviceCode = "urn:ietf:params:oauth:grant-type:device_code" + public static let tokenExchange = "urn:ietf:params:oauth:grant-type:token-exchange" + public static let ciba = "urn:ietf:params:oauth:grant-type:ciba" +} diff --git a/Sources/Constants/OAuth2ResponseTypes.swift b/Sources/Constants/OAuth2ResponseTypes.swift new file mode 100644 index 0000000..606dac3 --- /dev/null +++ b/Sources/Constants/OAuth2ResponseTypes.swift @@ -0,0 +1,48 @@ +public enum OAuth2ResponseTypes { + public static let code = "code" + public static let token = "token" + + /** + When supplied as the `response_type` parameter in an OAuth 2.0 Authorization Request, a successful response MUST + include the parameter `id_token`. The Authorization Server SHOULD NOT return an OAuth 2.0 Authorization Code, Access + Token, or Access Token Type in a successful response to the grant request. If a `redirect_uri` is supplied, the User + Agent SHOULD be redirected there after granting or denying access. The request MAY include a `state` parameter, and if + so, the Authorization Server MUST echo its value as a response parameter when issuing either a successful response or + an error response. The default Response Mode for this Response Type is the fragment encoding and the query encoding + MUST NOT be used. Both successful and error responses SHOULD be returned using the supplied Response Mode, or if none + is supplied, using the default Response Mode. + */ + public static let idToken = "id_token" + + /** + When supplied as the value for the `response_type` parameter, a successful response MUST include an Access Token, an + Access Token Type, and an `id_token`. The default Response Mode for this Response Type is the fragment encoding and the + query encoding MUST NOT be used. Both successful and error responses SHOULD be returned using the supplied Response + Mode, or if none is supplied, using the default Response Mode. + */ + public static let idTokenToken = "id_token token" + + /** + When supplied as the value for the `response_type` parameter, a successful response MUST include both an Authorization + Code and an `id_token`. The default Response Mode for this Response Type is the fragment encoding and the query + encoding MUST NOT be used. Both successful and error responses SHOULD be returned using the supplied Response Mode, or + if none is supplied, using the default Response Mode. + */ + public static let codeIdToken = "code id_token" + + /** + When supplied as the value for the `response_type` parameter, a successful response MUST include an Access Token, an + Access Token Type, and an Authorization Code. The default Response Mode for this Response Type is the fragment + encoding and the query encoding MUST NOT be used. Both successful and error responses SHOULD be returned using the + supplied Response Mode, or if none is supplied, using the default Response Mode. + */ + public static let codeToken = "code token" + + /** + When supplied as the value for the `response_type` parameter, a successful response MUST include an Authorization + Code, an `id_token`, an Access Token, and an Access Token Type. The default Response Mode for this Response Type is + the fragment encoding and the query encoding MUST NOT be used. Both successful and error responses SHOULD be returned + using the supplied Response Mode, or if none is supplied, using the default Response Mode. + */ + public static let codeIdTokenToken = "code id_token token" +} diff --git a/Sources/Constants/OAuth2TokenTypeIdentifiers.swift b/Sources/Constants/OAuth2TokenTypeIdentifiers.swift new file mode 100644 index 0000000..65b828f --- /dev/null +++ b/Sources/Constants/OAuth2TokenTypeIdentifiers.swift @@ -0,0 +1,8 @@ +public enum OAuth2TokenTypeIdentifiers { + public static let accessToken = "urn:ietf:params:oauth:token-type:access_token" + public static let identityToken = "urn:ietf:params:oauth:token-type:id_token" + public static let refreshToken = "urn:ietf:params:oauth:token-type:refresh_token" + public static let saml11 = "urn:ietf:params:oauth:token-type:saml1" + public static let saml2 = "urn:ietf:params:oauth:token-type:saml2" + public static let jwt = "urn:ietf:params:oauth:token-type:jwt" +} diff --git a/Sources/Flows/OAuth2.swift b/Sources/Flows/OAuth2.swift index 896aa67..a655661 100644 --- a/Sources/Flows/OAuth2.swift +++ b/Sources/Flows/OAuth2.swift @@ -21,6 +21,7 @@ import Foundation #if !NO_MODULE_IMPORT import Base + import Constants #if os(macOS) import macOS #elseif os(iOS) || os(visionOS) @@ -358,7 +359,7 @@ open class OAuth2: OAuth2Base { } let req = OAuth2AuthRequest(url: (clientConfig.refreshURL ?? clientConfig.tokenURL ?? clientConfig.authorizeURL)) - req.params["grant_type"] = "refresh_token" + req.params["grant_type"] = OAuth2GrantTypes.refreshToken req.params["refresh_token"] = refreshToken if let clientId = clientId { req.params["client_id"] = clientId @@ -423,11 +424,11 @@ open class OAuth2: OAuth2Base { } let req = OAuth2AuthRequest(url: (clientConfig.tokenURL ?? clientConfig.authorizeURL)) - req.params["grant_type"] = "urn:ietf:params:oauth:grant-type:token-exchange" + req.params["grant_type"] = OAuth2GrantTypes.tokenExchange req.params["audience"] = audienceClientId - req.params["requested_token_type"] = "urn:ietf:params:oauth:token-type:refresh_token" + req.params["requested_token_type"] = OAuth2TokenTypeIdentifiers.refreshToken req.params["subject_token"] = refreshToken - req.params["subject_token_type"] = "urn:ietf:params:oauth:token-type:refresh_token" + req.params["subject_token_type"] = OAuth2TokenTypeIdentifiers.refreshToken req.add(params: params) return req @@ -512,12 +513,12 @@ open class OAuth2: OAuth2Base { } let req = OAuth2AuthRequest(url: (clientConfig.tokenURL ?? clientConfig.authorizeURL)) - req.params["grant_type"] = "urn:ietf:params:oauth:grant-type:token-exchange" + req.params["grant_type"] = OAuth2GrantTypes.tokenExchange req.params["resource"] = resourceUrl.appendingPathComponent(resourcePath).absoluteString req.params["scope"] = clientConfig.scope - req.params["requested_token_type"] = "urn:ietf:params:oauth:token-type:access_token" + req.params["requested_token_type"] = OAuth2TokenTypeIdentifiers.accessToken req.params["subject_token"] = accessToken - req.params["subject_token_type"] = "urn:ietf:params:oauth:token-type:access_token" + req.params["subject_token_type"] = OAuth2TokenTypeIdentifiers.accessToken req.add(params: params) return req diff --git a/Sources/Flows/OAuth2ClientCredentials.swift b/Sources/Flows/OAuth2ClientCredentials.swift index dc44e4e..eb5e8c3 100644 --- a/Sources/Flows/OAuth2ClientCredentials.swift +++ b/Sources/Flows/OAuth2ClientCredentials.swift @@ -21,6 +21,7 @@ import Foundation #if !NO_MODULE_IMPORT import Base +import Constants #endif @@ -30,7 +31,7 @@ Class to handle two-legged OAuth2 requests of the "client_credentials" type. open class OAuth2ClientCredentials: OAuth2 { override open class var grantType: String { - return "client_credentials" + return OAuth2GrantTypes.clientCredentials } override open func doAuthorize(params inParams: OAuth2StringDict? = nil) { diff --git a/Sources/Flows/OAuth2CodeGrant.swift b/Sources/Flows/OAuth2CodeGrant.swift index f97a40a..8d01288 100644 --- a/Sources/Flows/OAuth2CodeGrant.swift +++ b/Sources/Flows/OAuth2CodeGrant.swift @@ -21,6 +21,7 @@ import Foundation #if !NO_MODULE_IMPORT import Base +import Constants #endif @@ -34,11 +35,11 @@ key will be embedded into the request body. open class OAuth2CodeGrant: OAuth2 { override open class var grantType: String { - return "authorization_code" + return OAuth2GrantTypes.authorizationCode } override open class var responseType: String? { - return "code" + return OAuth2ResponseTypes.code } diff --git a/Sources/Flows/OAuth2DeviceGrant.swift b/Sources/Flows/OAuth2DeviceGrant.swift index c838dac..5d48ba0 100644 --- a/Sources/Flows/OAuth2DeviceGrant.swift +++ b/Sources/Flows/OAuth2DeviceGrant.swift @@ -21,12 +21,13 @@ import Foundation #if !NO_MODULE_IMPORT import Base +import Constants #endif /// https://www.ietf.org/rfc/rfc8628.html open class OAuth2DeviceGrant: OAuth2 { override open class var grantType: String { - return "urn:ietf:params:oauth:grant-type:device_code" + return OAuth2GrantTypes.deviceCode } override open class var responseType: String? { diff --git a/Sources/Flows/OAuth2ImplicitGrant.swift b/Sources/Flows/OAuth2ImplicitGrant.swift index 3101f0b..7d6c310 100644 --- a/Sources/Flows/OAuth2ImplicitGrant.swift +++ b/Sources/Flows/OAuth2ImplicitGrant.swift @@ -21,6 +21,7 @@ import Foundation #if !NO_MODULE_IMPORT import Base +import Constants #endif @@ -30,11 +31,11 @@ Class to handle OAuth2 requests for public clients, such as distributed Mac/iOS open class OAuth2ImplicitGrant: OAuth2 { override open class var grantType: String { - return "implicit" + return OAuth2GrantTypes.implicit } override open class var responseType: String? { - return "token" + return OAuth2ResponseTypes.token } override open func handleRedirectURL(_ redirect: URL) { diff --git a/Sources/Flows/OAuth2PasswordGrant.swift b/Sources/Flows/OAuth2PasswordGrant.swift index 02c7ef8..8f9a186 100644 --- a/Sources/Flows/OAuth2PasswordGrant.swift +++ b/Sources/Flows/OAuth2PasswordGrant.swift @@ -21,6 +21,7 @@ import Foundation #if !NO_MODULE_IMPORT import Base + import Constants #if os(macOS) import macOS #elseif os(iOS) || os(visionOS) @@ -53,7 +54,7 @@ If no credentials are set when authorizing, a native controller is shown so that open class OAuth2PasswordGrant: OAuth2 { override open class var grantType: String { - return "password" + return OAuth2GrantTypes.password } override open class var clientIdMandatory: Bool {