Unauthorized Exception
Exception thrown when authentication fails (HTTP 401).
Indicates that the JWT token is invalid, expired, or missing. Authentication is required for all SEP-12 KYC operations. This error typically occurs when:
JWT token has expired
JWT token is malformed or tampered with
JWT token signature is invalid
Token was issued for a different account
SEP-10 authentication was not performed
Recovery actions:
Re-authenticate via SEP-10 WebAuth to obtain a fresh JWT token
Verify the token is being sent in the correct format
Check that the token matches the account being accessed
Example - Handle expired token:
suspend fun getCustomerInfoWithRetry(
kycService: KYCService,
webAuth: WebAuth,
accountId: String,
keyPair: KeyPair
): GetCustomerInfoResponse {
var jwt = getCurrentJwt() // Get cached token
try {
return kycService.getCustomerInfo(
GetCustomerInfoRequest(jwt = jwt, account = accountId)
)
} catch (e: UnauthorizedException) {
println("Token expired, re-authenticating...")
// Re-authenticate to get fresh token
val authToken = webAuth.jwtToken(
clientAccountId = accountId,
signers = listOf(keyPair)
)
jwt = authToken.token
saveJwt(jwt) // Cache new token
// Retry with new token
return kycService.getCustomerInfo(
GetCustomerInfoRequest(jwt = jwt, account = accountId)
)
}
}Example - Check token before use:
fun isTokenValid(token: String): Boolean {
return try {
val authToken = AuthToken.parse(token)
val now = Clock.System.now().toEpochMilliseconds() / 1000
authToken.exp > now
} catch (e: Exception) {
false
}
}
suspend fun getCustomerInfo(request: GetCustomerInfoRequest) {
if (!isTokenValid(request.jwt)) {
println("Token expired, please re-authenticate")
throw UnauthorizedException()
}
try {
kycService.getCustomerInfo(request)
} catch (e: UnauthorizedException) {
println("Authentication failed, check token")
}
}Example - Refresh token proactively:
class KYCClient(
private val kycService: KYCService,
private val webAuth: WebAuth
) {
private var currentToken: String? = null
private var tokenExpiry: Long = 0
suspend fun ensureValidToken(accountId: String, keyPair: KeyPair): String {
val now = Clock.System.now().toEpochMilliseconds() / 1000
// Refresh if token expires in less than 5 minutes
if (currentToken == null || tokenExpiry - now < 300) {
val authToken = webAuth.jwtToken(
clientAccountId = accountId,
signers = listOf(keyPair)
)
currentToken = authToken.token
tokenExpiry = authToken.exp
}
return currentToken!!
}
suspend fun getCustomerInfo(accountId: String, keyPair: KeyPair) {
val jwt = ensureValidToken(accountId, keyPair)
return kycService.getCustomerInfo(
GetCustomerInfoRequest(jwt = jwt, account = accountId)
)
}
}See also:
KYCException base class
WebAuth for SEP-10 authentication
AuthToken for parsing JWT tokens