Skip to content

Commit

Permalink
fix(auth): store session directly without wrapping in StoredSession t…
Browse files Browse the repository at this point in the history
…ype (#513)
  • Loading branch information
grdsdev committed Aug 26, 2024
1 parent a15efb1 commit 5de2d8d
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 65 deletions.
105 changes: 78 additions & 27 deletions Sources/Auth/Internal/SessionStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,61 +8,112 @@
import Foundation
import Helpers

/// A locally stored ``Session``, it contains metadata such as `expirationDate`.
struct StoredSession: Codable {
var session: Session
var expirationDate: Date

init(session: Session, expirationDate _: Date? = nil) {
self.session = session
expirationDate = Date(timeIntervalSince1970: session.expiresAt)
}
}

struct SessionStorage {
var get: @Sendable () throws -> Session?
var store: @Sendable (_ session: Session) throws -> Void
var delete: @Sendable () throws -> Void
}

extension SessionStorage {
/// Key used to store session on ``AuthLocalStorage``.
///
/// It uses value from ``AuthClient/Configuration/storageKey`` or default to `supabase.auth.token` if not provided.
static func key(_ clientID: AuthClientID) -> String {
Dependencies[clientID].configuration.storageKey ?? STORAGE_KEY
}

static func live(clientID: AuthClientID) -> SessionStorage {
var key: String {
Dependencies[clientID].configuration.storageKey ?? STORAGE_KEY
var storage: any AuthLocalStorage {
Dependencies[clientID].configuration.localStorage
}

var oldKey: String { "supabase.session" }
var logger: (any SupabaseLogger)? {
Dependencies[clientID].configuration.logger
}

var storage: any AuthLocalStorage {
Dependencies[clientID].configuration.localStorage
let migrations: [StorageMigration] = [
.sessionNewKey(clientID: clientID),
.storeSessionDirectly(clientID: clientID),
]

var key: String {
SessionStorage.key(clientID)
}

return SessionStorage(
get: {
var storedData = try? storage.retrieve(key: oldKey)

if let storedData {
// migrate to new key.
try storage.store(key: key, value: storedData)
try? storage.remove(key: oldKey)
} else {
storedData = try storage.retrieve(key: key)
for migration in migrations {
do {
try migration.run()
} catch {
logger?.error("Storage migration failed: \(error.localizedDescription)")
}
}

let storedData = try storage.retrieve(key: key)
return try storedData.flatMap {
try AuthClient.Configuration.jsonDecoder.decode(StoredSession.self, from: $0).session
try AuthClient.Configuration.jsonDecoder.decode(Session.self, from: $0)
}
},
store: { session in
try storage.store(
key: key,
value: AuthClient.Configuration.jsonEncoder.encode(StoredSession(session: session))
value: AuthClient.Configuration.jsonEncoder.encode(session)
)
},
delete: {
try storage.remove(key: key)
try? storage.remove(key: oldKey)
}
)
}
}

struct StorageMigration {
var run: @Sendable () throws -> Void
}

extension StorageMigration {
/// Migrate stored session from `supabase.session` key to the custom provided storage key
/// or the default `supabase.auth.token` key.
static func sessionNewKey(clientID: AuthClientID) -> StorageMigration {
StorageMigration {
let storage = Dependencies[clientID].configuration.localStorage
let newKey = SessionStorage.key(clientID)

if let storedData = try? storage.retrieve(key: "supabase.session") {
// migrate to new key.
try storage.store(key: newKey, value: storedData)
try? storage.remove(key: "supabase.session")
}
}
}

/// Migrate the stored session.
///
/// Migrate the stored session which used to be stored as:
/// ```json
/// {
/// "session": <Session>,
/// "expiration_date": <Date>
/// }
/// ```
/// To directly store the `Session` object.
static func storeSessionDirectly(clientID: AuthClientID) -> StorageMigration {
struct StoredSession: Codable {
var session: Session
var expirationDate: Date
}

return StorageMigration {
let storage = Dependencies[clientID].configuration.localStorage
let key = SessionStorage.key(clientID)

if let data = try? storage.retrieve(key: key),
let storedSession = try? AuthClient.Configuration.jsonDecoder.decode(StoredSession.self, from: data)
{
let session = try AuthClient.Configuration.jsonEncoder.encode(storedSession.session)
try storage.store(key: key, value: session)
}
}
}
}
73 changes: 35 additions & 38 deletions Tests/AuthTests/Resources/local-storage.json
Original file line number Diff line number Diff line change
@@ -1,45 +1,42 @@
{
"supabase.auth.token" : {
"expiration_date" : "2024-04-01T13:25:07.000Z",
"session" : {
"access_token" : "accesstoken",
"expires_at" : 1711977907,
"expires_in" : 120,
"refresh_token" : "refreshtoken",
"token_type" : "bearer",
"user" : {
"app_metadata" : {
"access_token" : "accesstoken",
"expires_at" : 1711977907,
"expires_in" : 120,
"refresh_token" : "refreshtoken",
"token_type" : "bearer",
"user" : {
"app_metadata" : {
"provider" : "email",
"providers" : [
"email"
]
},
"aud" : "authenticated",
"confirmation_sent_at" : "2022-04-09T11:57:01.000Z",
"created_at" : "2022-04-09T11:57:01.000Z",
"email" : "[email protected]",
"id" : "859F402D-B3DE-4105-A1B9-932836D9193B",
"identities" : [
{
"created_at" : "2022-04-09T11:57:01.000Z",
"id" : "859f402d-b3de-4105-a1b9-932836d9193b",
"identity_data" : {
"sub" : "859f402d-b3de-4105-a1b9-932836d9193b"
},
"identity_id" : "859F402D-B3DE-4105-A1B9-932836D9193B",
"last_sign_in_at" : "2022-04-09T11:57:01.000Z",
"provider" : "email",
"providers" : [
"email"
]
},
"aud" : "authenticated",
"confirmation_sent_at" : "2022-04-09T11:57:01.000Z",
"created_at" : "2022-04-09T11:57:01.000Z",
"email" : "[email protected]",
"id" : "859F402D-B3DE-4105-A1B9-932836D9193B",
"identities" : [
{
"created_at" : "2022-04-09T11:57:01.000Z",
"id" : "859f402d-b3de-4105-a1b9-932836d9193b",
"identity_data" : {
"sub" : "859f402d-b3de-4105-a1b9-932836d9193b"
},
"identity_id" : "859F402D-B3DE-4105-A1B9-932836D9193B",
"last_sign_in_at" : "2022-04-09T11:57:01.000Z",
"provider" : "email",
"updated_at" : "2022-04-09T11:57:01.000Z",
"user_id" : "859F402D-B3DE-4105-A1B9-932836D9193B"
}
],
"is_anonymous" : false,
"phone" : "",
"role" : "authenticated",
"updated_at" : "2022-04-09T11:57:01.000Z",
"user_metadata" : {
"referrer_id" : null
"updated_at" : "2022-04-09T11:57:01.000Z",
"user_id" : "859F402D-B3DE-4105-A1B9-932836D9193B"
}
],
"is_anonymous" : false,
"phone" : "",
"role" : "authenticated",
"updated_at" : "2022-04-09T11:57:01.000Z",
"user_metadata" : {
"referrer_id" : null
}
}
}
Expand Down

0 comments on commit 5de2d8d

Please sign in to comment.