Skip to content

Commit 34c8c38

Browse files
fotiDimossus-lib
authored andcommitted
Add refresh uri setting (p2#330)
1 parent 8a035f7 commit 34c8c38

File tree

7 files changed

+72
-2
lines changed

7 files changed

+72
-2
lines changed

CONTRIBUTORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Contributors
33

44
Contributors to the codebase, in reverse chronological order:
55

6+
- Foti Dim, @fotidim
67
- Larry Brunet, @larrybrunet
78
- Dave Carlson, @drdavec
89
- Sam Oakley, @blork

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ oauth2.authConfig.authorizeEmbedded = true
6666
oauth2.authConfig.authorizeContext = <# your UIViewController / NSWindow #>
6767
```
6868

69+
Need to specify a separate refresh token URI? You can set the `refresh_uri` in the Settings Dictionary. If specified the library will refresh access tokens using the `refresh_uri` you specified, otherwise it will use the `token_uri`.
70+
6971
Need to debug? Use a `.debug` or even a `.trace` logger:
7072

7173
```swift
@@ -543,4 +545,3 @@ Since there is no `NOTICE` file there is nothing that you have to include in you
543545

544546

545547
[sample]: https://github.com/p2/OAuth2App
546-

Sources/Base/OAuth2Base.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ open class OAuth2Base: OAuth2Securable {
155155
- client_secret (String), usually only needed for code grant
156156
- authorize_uri (URL-String)
157157
- token_uri (URL-String), if omitted the authorize_uri will be used to obtain tokens
158+
- refresh_uri (URL-String), if omitted the token_uri will be used to obtain tokens
158159
- redirect_uris (Array of URL-Strings)
159160
- scope (String)
160161

Sources/Base/OAuth2ClientConfig.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ open class OAuth2ClientConfig {
2828

2929
/// The URL where we can exchange a code for a token.
3030
public final var tokenURL: URL?
31+
32+
/// The URL where we can refresh an access token using a refresh token.
33+
public final var refreshURL: URL?
3134

3235
/// Where a logo/icon for the app can be found.
3336
public final var logoURL: URL?
@@ -112,6 +115,9 @@ open class OAuth2ClientConfig {
112115
if let token = settings["token_uri"] as? String {
113116
tokenURL = URL(string: token)
114117
}
118+
if let refresh = settings["refresh_uri"] as? String {
119+
refreshURL = URL(string: refresh)
120+
}
115121
if let registration = settings["registration_uri"] as? String {
116122
registrationURL = URL(string: registration)
117123
}

Sources/Flows/OAuth2.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ open class OAuth2: OAuth2Base {
5757
- client_secret (String), usually only needed for code grant
5858
- authorize_uri (URL-String)
5959
- token_uri (URL-String), if omitted the authorize_uri will be used to obtain tokens
60+
- refresh_uri (URL-String), if omitted the token_uri will be used to obtain tokens
6061
- redirect_uris (Array of URL-Strings)
6162
- scope (String)
6263

@@ -343,7 +344,7 @@ open class OAuth2: OAuth2Base {
343344
throw OAuth2Error.noRefreshToken
344345
}
345346

346-
let req = OAuth2AuthRequest(url: (clientConfig.tokenURL ?? clientConfig.authorizeURL))
347+
let req = OAuth2AuthRequest(url: (clientConfig.refreshURL ?? clientConfig.tokenURL ?? clientConfig.authorizeURL))
347348
req.params["grant_type"] = "refresh_token"
348349
req.params["refresh_token"] = refreshToken
349350
if let clientId = clientId {

Tests/BaseTests/OAuth2Tests.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,18 @@ class OAuth2Tests: XCTestCase {
4343
"keychain": false,
4444
])
4545
}
46+
47+
func refreshOAuth2() -> OAuth2 {
48+
return OAuth2(settings: [
49+
"client_id": "abc",
50+
"authorize_uri": "https://auth.ful.io",
51+
"token_uri": "https://token.ful.io",
52+
"refresh_uri": "https://refresh.ful.io",
53+
"scope": "login",
54+
"verbose": true,
55+
"keychain": false,
56+
])
57+
}
4658

4759
func testInit() {
4860
var oauth = OAuth2(settings: ["client_id": "def"])
@@ -88,6 +100,22 @@ class OAuth2Tests: XCTestCase {
88100
//XCTAssertEqual(params["redirect_uri"]!, "oauth2app://callback", "Expecting correct `redirect_uri` in query")
89101
XCTAssertNil(params["state"], "Expecting no `state` in query")
90102
}
103+
104+
func testTokenRefreshRequest() {
105+
let oa = refreshOAuth2()
106+
oa.verbose = false
107+
oa.clientConfig.refreshToken = "abc"
108+
let req = try! oa.tokenRequestForTokenRefresh().asURLRequest(for: oa)
109+
let auth = req.url!
110+
111+
let comp = URLComponents(url: auth, resolvingAgainstBaseURL: true)!
112+
XCTAssertEqual("https", comp.scheme!, "Need correct scheme")
113+
XCTAssertEqual("refresh.ful.io", comp.host!, "Need correct host")
114+
115+
let params = OAuth2.params(fromQuery: comp.percentEncodedQuery ?? "")
116+
//XCTAssertEqual(params["redirect_uri"]!, "oauth2app://callback", "Expecting correct `redirect_uri` in query")
117+
XCTAssertNil(params["state"], "Expecting no `state` in query")
118+
}
91119

92120
func testAuthorizeCall() {
93121
let oa = genericOAuth2()

Tests/FlowTests/OAuth2RefreshTokenTests.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@ class OAuth2RefreshTokenTests: XCTestCase {
4141
"keychain": false,
4242
])
4343
}
44+
45+
func refreshOAuth2() -> OAuth2 {
46+
return OAuth2(settings: [
47+
"client_id": "abc",
48+
"authorize_uri": "https://auth.ful.io",
49+
"token_uri": "https://token.ful.io",
50+
"refresh_uri": "https://refresh.ful.io",
51+
"keychain": false,
52+
])
53+
}
4454

4555
func testCannotRefresh() {
4656
let oauth = genericOAuth2()
@@ -76,6 +86,28 @@ class OAuth2RefreshTokenTests: XCTestCase {
7686
XCTAssertNil(dict["client_secret"])
7787
XCTAssertNil(req!.allHTTPHeaderFields?["Authorization"])
7888
}
89+
90+
func testRefreshRequestWithDedicatedRefreshURI() {
91+
let oauth = refreshOAuth2()
92+
oauth.clientConfig.refreshToken = "pov"
93+
94+
let req = try? oauth.tokenRequestForTokenRefresh().asURLRequest(for: oauth)
95+
XCTAssertNotNil(req)
96+
XCTAssertNotNil(req?.url)
97+
XCTAssertNotNil(req?.httpBody)
98+
XCTAssertEqual("https://refresh.ful.io", req!.url!.absoluteString)
99+
let comp = URLComponents(url: req!.url!, resolvingAgainstBaseURL: true)
100+
let params = comp?.percentEncodedQuery
101+
XCTAssertNil(params)
102+
let body = String(data: req!.httpBody!, encoding: String.Encoding.utf8)
103+
XCTAssertNotNil(body)
104+
let dict = OAuth2.params(fromQuery: body!)
105+
XCTAssertEqual(dict["client_id"], "abc")
106+
XCTAssertEqual(dict["refresh_token"], "pov")
107+
XCTAssertEqual(dict["grant_type"], "refresh_token")
108+
XCTAssertNil(dict["client_secret"])
109+
XCTAssertNil(req!.allHTTPHeaderFields?["Authorization"])
110+
}
79111

80112
func testRefreshRequestWithSecret() {
81113
let oauth = genericOAuth2()

0 commit comments

Comments
 (0)