Skip to content
Open
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
1 change: 1 addition & 0 deletions source/api/api/api.api
Original file line number Diff line number Diff line change
Expand Up @@ -4640,6 +4640,7 @@ public final class com/clerk/api/session/Session {
public final fun getCurrentTask ()Lcom/clerk/api/session/SessionTask;
public final fun getExpireAt ()J
public final fun getFactorVerificationAge ()Ljava/util/List;
public final fun getHasMaximumLifetime ()Z
public final fun getId ()Ljava/lang/String;
public final fun getLastActiveAt ()J
public final fun getLastActiveOrganizationId ()Ljava/lang/String;
Expand Down
15 changes: 15 additions & 0 deletions source/api/src/main/kotlin/com/clerk/api/session/Session.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,15 @@ import kotlinx.serialization.Serializable
public data class Session(
val id: String,
val status: SessionStatus = SessionStatus.UNKNOWN,
/**
* When the session reaches its maximum lifetime, in milliseconds since epoch. Zero means the
* session has no maximum lifetime; see [hasMaximumLifetime].
*/
@SerialName("expire_at") val expireAt: Long,
/**
* When the session will be abandoned due to inactivity, in milliseconds since epoch. Zero means
* the session has no inactivity deadline.
*/
@SerialName("abandon_at") val abandonAt: Long? = null,
@SerialName("last_active_at") val lastActiveAt: Long,
@SerialName("latest_activity") val latestActivity: SessionActivity? = null,
Expand All @@ -61,6 +69,13 @@ public data class Session(
val tasks: List<SessionTask> = emptyList(),
@SerialName("last_active_token") val lastActiveToken: TokenResource? = null,
) {
/**
* Whether the session has a maximum lifetime. False when [expireAt] is zero. This says nothing
* about whether the session is active; use [status] for that.
*/
public val hasMaximumLifetime: Boolean
get() = expireAt > 0

@OptIn(ExperimentalSerializationApi::class)
@KeepGeneratedSerializer
@Serializable(with = SessionStatus.Serializer::class)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.clerk.api.session

import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test

class SessionLifetimeTest {

@Test
fun `a zero expire_at has no maximum lifetime`() {
assertFalse(indefiniteSession().hasMaximumLifetime)
}

@Test
fun `a future expire_at has a maximum lifetime`() {
assertTrue(indefiniteSession().copy(expireAt = 2_000_000_000_000L).hasMaximumLifetime)
}

@Test
fun `a revoked session with a zero expire_at has no maximum lifetime`() {
assertFalse(indefiniteSession().copy(status = Session.SessionStatus.REVOKED).hasMaximumLifetime)
}

@Test
fun `zero deadlines decode as zero`() {
val session = indefiniteSession()

assertEquals(0L, session.expireAt)
assertEquals(0L, session.abandonAt)
assertEquals(Session.SessionStatus.ACTIVE, session.status)
}

@Test
fun `an indefinite session survives a serialization round trip`() {
val session = indefiniteSession()

assertEquals(session, Json.decodeFromString<Session>(Json.encodeToString(session)))
}

private fun indefiniteSession(): Session =
Json.decodeFromString(
"""{
"id":"sess_native","status":"active","expire_at":0,"abandon_at":0,
"last_active_at":1,"created_at":1,"updated_at":1
}"""
)
}
Loading