Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions Sources/OAuthKit/OAuth+Token.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,50 @@ extension OAuth {
/// See: https://datatracker.ietf.org/doc/html/rfc6749#section-5.1
public struct Token: Codable, Equatable, Sendable {

/// The access token string as issued by the authorization server.
public let accessToken: String

/// If the access token will expire, then this can be used to obtain another access token.
public let refreshToken: String?

/// If the access token expires, this is the duration of time the access token is granted for (in seconds).
public let expiresIn: Int?
public let state: String?

/// If the scope the user granted is identical to the scope the app requested, this parameter is optional.
/// If the granted scope is different from the requested scope, such as if the user modified the scope, then this parameter is required.
public let scope: String?

/// The type of token this is, typically just the string “Bearer”.
public let type: String

public init(accessToken: String, refreshToken: String?, expiresIn: Int?, state: String?, type: String) {
/// The OpenID Connect issued by the authorization server.
/// This token is included if the authorization server supports OpenID connect and the scope included `openid`
public let openIDToken: String?

/// Common Initializer.
/// - Parameters:
/// - accessToken: the access token string
/// - refreshToken: the refresh token
/// - expiresIn: the expiration time in secods
/// - scope: the scope returned from the authorization server
/// - type: the token type
/// - openIDToken: the OpenID Connect token
public init(accessToken: String, refreshToken: String?, expiresIn: Int?, scope: String?, type: String, openIDToken: String? = nil) {
self.accessToken = accessToken
self.refreshToken = refreshToken
self.expiresIn = expiresIn
self.state = state
self.scope = scope
self.type = type
self.openIDToken = openIDToken
}

enum CodingKeys: String, CodingKey {
case accessToken = "access_token"
case refreshToken = "refresh_token"
case expiresIn = "expires_in"
case type = "token_type"
case state
case scope
case openIDToken = "id_token"
}
}

Expand Down
2 changes: 1 addition & 1 deletion Tests/OAuthKitTests/CodableTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ struct CodableTests {
@Test("Encoding and Decoding Tokens")
func whenEncodingDecodingTokens() async throws {

let token: OAuth.Token = .init(accessToken: UUID().uuidString, refreshToken: UUID().uuidString, expiresIn: 3600, state: "xyz", type: "bearer")
let token: OAuth.Token = .init(accessToken: UUID().uuidString, refreshToken: UUID().uuidString, expiresIn: 3600, scope: "openid", type: "bearer")

let data = try encoder.encode(token)
let decoded: OAuth.Token = try decoder.decode(OAuth.Token.self, from: data)
Expand Down
4 changes: 2 additions & 2 deletions Tests/OAuthKitTests/KeychainTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ final class KeychainTests {
func whenStoring() async throws {
let keychain = Keychain.default
let key = "Github"
let token: OAuth.Token = .init(accessToken: "1234", refreshToken: nil, expiresIn: 3600, state: "x", type: "bearer")
let token: OAuth.Token = .init(accessToken: "1234", refreshToken: nil, expiresIn: 3600, scope: "email", type: "bearer")

let inserted = try! keychain.set(token, for: key)
#expect(inserted == true)
Expand All @@ -29,7 +29,7 @@ final class KeychainTests {
#expect(token.accessToken.isNotEmpty)
#expect(token.accessToken == found.accessToken)
#expect(token.expiresIn == found.expiresIn)
#expect(token.state == found.state)
#expect(token.scope == found.scope)
#expect(token.type == found.type)

let keys = keychain.keys.filter{ $0.contains("oauth")}
Expand Down
2 changes: 1 addition & 1 deletion Tests/OAuthKitTests/OAuthTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ final class OAuthTests {
@Test("Building Refresh Token Request")
func whenBuildingRefreshTokenRequest() async throws {
let provider = await oauth.providers[0]
let token: OAuth.Token = .init(accessToken: UUID().uuidString, refreshToken: UUID().uuidString, expiresIn: 3600, state: nil, type: "bearer")
let token: OAuth.Token = .init(accessToken: UUID().uuidString, refreshToken: UUID().uuidString, expiresIn: 3600, scope: nil, type: "bearer")
let request = OAuth.Request.refresh(provider: provider, token: token)
#expect(request != nil)
#expect(request!.url!.absoluteString.contains("client_id="))
Expand Down