diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthSession.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthSession.kt index 7f31374087..63f37af112 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthSession.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/AWSCognitoAuthSession.kt @@ -99,7 +99,7 @@ internal fun AmplifyCredential.getCognitoSession( } return try { - AuthSessionResult.success(userPoolTokens?.accessToken?.let(SessionHelper::getUserSub)) + AuthSessionResult.success(userPoolTokens?.accessToken?.userSub) } catch (e: Exception) { AuthSessionResult.failure(UnknownException(cause = e)) } @@ -115,9 +115,9 @@ internal fun AmplifyCredential.getCognitoSession( return AuthSessionResult.success( AWSCognitoUserPoolTokens( - accessToken = cognitoUserPoolTokens.accessToken, - idToken = cognitoUserPoolTokens.idToken, - refreshToken = cognitoUserPoolTokens.refreshToken + accessToken = cognitoUserPoolTokens.accessToken?.tokenValue, + idToken = cognitoUserPoolTokens.idToken?.tokenValue, + refreshToken = cognitoUserPoolTokens.refreshToken?.tokenValue ) ) } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/FetchAuthSessionCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/FetchAuthSessionCognitoActions.kt index 1bc0a8c997..3efdd257e3 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/FetchAuthSessionCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/FetchAuthSessionCognitoActions.kt @@ -20,7 +20,6 @@ import aws.sdk.kotlin.services.cognitoidentity.model.GetIdRequest import aws.sdk.kotlin.services.cognitoidentityprovider.getTokensFromRefreshToken import aws.smithy.kotlin.runtime.time.Instant import com.amplifyframework.auth.cognito.AuthEnvironment -import com.amplifyframework.auth.cognito.helpers.SessionHelper import com.amplifyframework.auth.exceptions.NotAuthorizedException import com.amplifyframework.auth.exceptions.SessionExpiredException import com.amplifyframework.auth.exceptions.SignedOutException @@ -48,7 +47,7 @@ internal object FetchAuthSessionCognitoActions : FetchAuthSessionActions { val deviceMetadata: DeviceMetadata.Metadata? = getDeviceMetadata(username) val response = cognitoAuthService.cognitoIdentityProviderClient?.getTokensFromRefreshToken { - refreshToken = tokens.refreshToken + refreshToken = tokens.refreshToken?.tokenValue clientId = configuration.userPool?.appClient clientSecret = configuration.userPool?.appClientSecret deviceKey = deviceMetadata?.deviceKey @@ -58,13 +57,13 @@ internal object FetchAuthSessionCognitoActions : FetchAuthSessionActions { val refreshedUserPoolTokens = CognitoUserPoolTokens( idToken = response?.authenticationResult?.idToken, accessToken = response?.authenticationResult?.accessToken, - refreshToken = response?.authenticationResult?.refreshToken ?: tokens.refreshToken, + refreshToken = response?.authenticationResult?.refreshToken ?: tokens.refreshToken?.tokenValue, expiration = Instant.now().plus(expiresIn.seconds).epochSeconds ) val updatedSignedInData = signedInData.copy( - userId = refreshedUserPoolTokens.accessToken?.let(SessionHelper::getUserSub) ?: signedInData.userId, - username = refreshedUserPoolTokens.accessToken?.let(SessionHelper::getUsername) ?: username, + userId = refreshedUserPoolTokens.accessToken?.userSub ?: signedInData.userId, + username = refreshedUserPoolTokens.accessToken?.username ?: username, cognitoUserPoolTokens = refreshedUserPoolTokens ) diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/HostedUICognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/HostedUICognitoActions.kt index eba02da963..6602e1b6e5 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/HostedUICognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/HostedUICognitoActions.kt @@ -17,7 +17,6 @@ package com.amplifyframework.auth.cognito.actions import com.amplifyframework.auth.cognito.AuthEnvironment import com.amplifyframework.auth.cognito.exceptions.configuration.InvalidOauthConfigurationException -import com.amplifyframework.auth.cognito.helpers.JWTParser import com.amplifyframework.statemachine.Action import com.amplifyframework.statemachine.codegen.actions.HostedUIActions import com.amplifyframework.statemachine.codegen.data.DeviceMetadata @@ -54,8 +53,8 @@ internal object HostedUICognitoActions : HostedUIActions { if (hostedUIClient == null) throw InvalidOauthConfigurationException() val token = hostedUIClient.fetchToken(event.uri) - val userId = token.accessToken?.let { JWTParser.getClaim(it, "sub") } ?: "" - val username = token.accessToken?.let { JWTParser.getClaim(it, "username") } ?: "" + val userId = token.accessToken?.userSub ?: "" + val username = token.accessToken?.username ?: "" val signedInData = SignedInData( userId, diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCognitoActions.kt index 328a90a2f4..8baa3312db 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignInCognitoActions.kt @@ -126,7 +126,7 @@ internal object SignInCognitoActions : SignInActions { cognitoAuthService.cognitoIdentityProviderClient?.confirmDevice( ConfirmDeviceRequest.invoke { - this.accessToken = event.signedInData.cognitoUserPoolTokens.accessToken + this.accessToken = event.signedInData.cognitoUserPoolTokens.accessToken?.tokenValue this.deviceKey = deviceKey this.deviceName = Build.MODEL this.deviceSecretVerifierConfig = DeviceSecretVerifierConfigType.invoke { diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignOutCognitoActions.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignOutCognitoActions.kt index b3a995927f..021919e4f9 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignOutCognitoActions.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/actions/SignOutCognitoActions.kt @@ -19,7 +19,6 @@ import aws.sdk.kotlin.services.cognitoidentityprovider.model.GlobalSignOutReques import aws.sdk.kotlin.services.cognitoidentityprovider.model.RevokeTokenRequest import com.amplifyframework.auth.cognito.AuthEnvironment import com.amplifyframework.auth.cognito.exceptions.configuration.InvalidOauthConfigurationException -import com.amplifyframework.auth.cognito.helpers.JWTParser import com.amplifyframework.statemachine.Action import com.amplifyframework.statemachine.codegen.actions.SignOutActions import com.amplifyframework.statemachine.codegen.data.DeviceMetadata @@ -76,7 +75,7 @@ internal object SignOutCognitoActions : SignOutActions { val accessToken = event.signedInData.cognitoUserPoolTokens.accessToken val evt = try { cognitoAuthService.cognitoIdentityProviderClient?.globalSignOut( - GlobalSignOutRequest { this.accessToken = accessToken } + GlobalSignOutRequest { this.accessToken = accessToken?.tokenValue } ) SignOutEvent( SignOutEvent.EventType.RevokeToken(event.signedInData, hostedUIErrorData = event.hostedUIErrorData) @@ -84,7 +83,7 @@ internal object SignOutCognitoActions : SignOutActions { } catch (e: Exception) { logger.warn("Failed to sign out globally.", e) val globalSignOutErrorData = GlobalSignOutErrorData( - accessToken = accessToken, + accessToken = accessToken?.tokenValue, error = e ) SignOutEvent( @@ -106,19 +105,19 @@ internal object SignOutCognitoActions : SignOutActions { val refreshToken = event.signedInData.cognitoUserPoolTokens.refreshToken val evt = try { // Check for "origin_jti" claim in access token, else skip revoking - if (accessToken?.let { JWTParser.hasClaim(it, "origin_jti") } == true) { + if (accessToken?.tokenRevocationId != null) { cognitoAuthService.cognitoIdentityProviderClient?.revokeToken( RevokeTokenRequest { clientId = configuration.userPool?.appClient clientSecret = configuration.userPool?.appClientSecret - token = refreshToken + token = refreshToken?.tokenValue } ) SignOutEvent(SignOutEvent.EventType.SignOutLocally(event.signedInData, event.hostedUIErrorData)) } else { logger.debug("Access Token does not contain `origin_jti` claim. Skip revoking tokens.") val error = RevokeTokenErrorData( - refreshToken = refreshToken, + refreshToken = refreshToken?.tokenValue, error = Exception("Access Token does not contain `origin_jti` claim. Skip revoking tokens.") ) @@ -134,7 +133,7 @@ internal object SignOutCognitoActions : SignOutActions { } catch (e: Exception) { logger.warn("Failed to revoke tokens.", e) val error = RevokeTokenErrorData( - refreshToken = refreshToken, + refreshToken = refreshToken?.tokenValue, error = e ) @@ -156,7 +155,7 @@ internal object SignOutCognitoActions : SignOutActions { logger.verbose("$id Starting execution") val error = RevokeTokenErrorData( - refreshToken = event.signedInData.cognitoUserPoolTokens.refreshToken, + refreshToken = event.signedInData.cognitoUserPoolTokens.refreshToken?.tokenValue, error = Exception("RevokeToken not attempted because GlobalSignOut failed.") ) diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoLegacyCredentialStore.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoLegacyCredentialStore.kt index 1ded7dd888..817c7f57dc 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoLegacyCredentialStore.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/data/AWSCognitoLegacyCredentialStore.kt @@ -19,7 +19,6 @@ import android.content.Context import androidx.core.content.edit import com.amplifyframework.auth.AuthProvider import com.amplifyframework.auth.cognito.AuthConfiguration -import com.amplifyframework.auth.cognito.helpers.SessionHelper import com.amplifyframework.auth.cognito.helpers.identityProviderName import com.amplifyframework.core.store.KeyValueRepository import com.amplifyframework.statemachine.codegen.data.AWSCredentials @@ -216,13 +215,13 @@ internal class AWSCognitoLegacyCredentialStore( val signInMethod = retrieveUserPoolSignInMethod() ?: return null val tokenUserId = try { - cognitoUserPoolTokens.accessToken?.let { SessionHelper.getUserSub(it) } ?: "" + cognitoUserPoolTokens.accessToken?.userSub ?: "" } catch (e: Exception) { "" } val tokenUsername = try { - cognitoUserPoolTokens.accessToken?.let { SessionHelper.getUsername(it) } ?: "" + cognitoUserPoolTokens.accessToken?.username ?: "" } catch (e: Exception) { "" } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/JWTParser.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/JWTParser.kt deleted file mode 100644 index 3741ed1048..0000000000 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/JWTParser.kt +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package com.amplifyframework.auth.cognito.helpers - -import android.util.Base64 -import com.amplifyframework.auth.exceptions.UnknownException -import kotlin.text.Charsets.UTF_8 -import org.json.JSONObject - -/** - * Utility class for all operations on JWT. - */ -internal object JWTParser { - private const val HEADER = 0 - private const val PAYLOAD = 1 - private const val SIGNATURE = 2 - private const val JWT_PARTS = 3 - - /** - * Returns header for a JWT as a JSON object. - * - * @param jwt valid JSON Web Token as String. - * @return header as a JSONObject. - */ - fun getHeader(jwt: String): JSONObject = try { - validateJWT(jwt) - val sectionDecoded = - Base64.decode(jwt.split(".").toTypedArray()[HEADER], Base64.URL_SAFE) - val jwtSection = String(sectionDecoded, UTF_8) - JSONObject(jwtSection) - } catch (e: Exception) { - throw UnknownException("${e.localizedMessage ?: ""}, error in parsing JSON") - } - - /** - * Returns payload of a JWT as a JSON object. - * - * @param jwt valid JSON Web Token as String. - * @return payload as a JSONObject. - */ - fun getPayload(jwt: String): JSONObject = try { - validateJWT(jwt) - val payload = jwt.split(".").toTypedArray()[PAYLOAD] - val sectionDecoded = Base64.decode(payload, Base64.URL_SAFE) - val jwtSection = String(sectionDecoded, UTF_8) - JSONObject(jwtSection) - } catch (e: Exception) { - throw UnknownException("${e.localizedMessage ?: ""}, error in parsing JSON") - } - - /** - * Returns signature of a JWT as a String. - * - * @param jwt valid JSON Web Token as String. - * @return signature as a String. - */ - fun getSignature(jwt: String): String = try { - validateJWT(jwt) - val sectionDecoded = - Base64.decode(jwt.split(".").toTypedArray()[SIGNATURE], Base64.URL_SAFE) - String(sectionDecoded, UTF_8) - } catch (e: Exception) { - throw UnknownException("${e.localizedMessage ?: ""}, error in parsing JSON") - } - - /** - * Returns a claim, from the `JWT`s' payload, as a String. - * - * @param jwt valid JSON Web Token as String. - * @param claim claim name as String. - * @return claim from the JWT as a String. - */ - fun getClaim(jwt: String, claim: String?): String? { - if (jwt.isEmpty()) { - return jwt - } - return try { - val payload = getPayload(jwt) - val claimValue = claim?.let { payload[claim] } - claimValue.toString() - } catch (e: Exception) { - throw UnknownException("${e.localizedMessage ?: ""}, Invalid token") - } - } - - /** - * Checks if a JWT token contains a claim. - * @param jwt A string, possibly not event a JWT - * @param key Key for a claim, e.g., "jti" or "aud" - * @return True if JWT is a valid JWT and contains the requested claim, false otherwise - */ - fun hasClaim(jwt: String, key: String?): Boolean = try { - getPayload(jwt).has(key) - } catch (e: Exception) { - false - } - - /** - * Checks if `JWT` is a valid JSON Web Token. - * - * @param jwt The JWT as a [String]. - */ - fun validateJWT(jwt: String) { - // Check if the the JWT has the three parts - val jwtParts = jwt.split(".").toTypedArray() - if (jwtParts.size != JWT_PARTS) { - throw UnknownException("Not a JSON web token. Error in parsing JSON") - } - } -} diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/SessionHelper.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/SessionHelper.kt index 458077b67d..050372a212 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/SessionHelper.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/SessionHelper.kt @@ -21,29 +21,6 @@ import java.time.Instant import java.time.temporal.ChronoUnit internal object SessionHelper { - /** - * Returns expiration of this id token. - * @return id token expiration claim as {@link java.time.Instant} in UTC. - */ - internal fun getExpiration(token: String): Instant? { - val claim = JWTParser.getClaim(token, "exp") - return claim?.let { - Instant.ofEpochSecond(claim.toLong()) - } - } - - /** - * Returns the username set in the access token. - * @return Username. - */ - fun getUsername(token: String): String? = JWTParser.getClaim(token, "username") - - /** - * Returns the usersub set in the access token. - * @return usersub - */ - fun getUserSub(token: String): String? = JWTParser.getClaim(token, "sub") - /** * Returns true if the access and id tokens have not expired. * @return boolean to indicate if the access and id tokens are expired. @@ -53,10 +30,9 @@ internal object SessionHelper { return when { userPoolTokens.idToken == null -> false userPoolTokens.accessToken == null -> false - else -> currentTimeStamp < getExpiration(userPoolTokens.idToken) && - currentTimeStamp < getExpiration( - userPoolTokens.accessToken - ) + else -> + currentTimeStamp < userPoolTokens.idToken.expiration && + currentTimeStamp < userPoolTokens.accessToken.expiration } } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/SignInChallengeHelper.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/SignInChallengeHelper.kt index f2c1e4970d..63322345e1 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/SignInChallengeHelper.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/auth/cognito/helpers/SignInChallengeHelper.kt @@ -59,9 +59,9 @@ internal object SignInChallengeHelper { ): StateMachineEvent = when { authenticationResult != null -> { authenticationResult.let { - val userId = it.accessToken?.let { token -> SessionHelper.getUserSub(token) } ?: "" - val expiresIn = Instant.now().plus(it.expiresIn.seconds).epochSeconds - val tokens = CognitoUserPoolTokens(it.idToken, it.accessToken, it.refreshToken, expiresIn) + val expiration = Instant.now().plus(it.expiresIn.seconds).epochSeconds + val tokens = CognitoUserPoolTokens(it.idToken, it.accessToken, it.refreshToken, expiration) + val userId = tokens.accessToken?.userSub ?: "" val signedInData = SignedInData( userId, username, diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/AmplifyCredential.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/AmplifyCredential.kt index 4b0784e386..fdddfaff6f 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/AmplifyCredential.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/AmplifyCredential.kt @@ -15,6 +15,7 @@ package com.amplifyframework.statemachine.codegen.data +import com.amplifyframework.statemachine.util.mask import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -81,40 +82,11 @@ internal sealed class AmplifyCredential { @Serializable internal data class FederatedToken(val token: String, val providerName: String) { override fun toString(): String = "FederatedToken(" + - "token = ${token.substring(0..4)}***, " + + "token = ${token.mask()}, " + "providerName = $providerName" + ")" } -/** - * Contains cognito user pool JWT tokens - * @param idToken User Pool id token - * @param accessToken User Pool access token - * @param refreshToken User Pool refresh token - * @param expiration Auth result expiration but not token expiration - */ -@Serializable -internal data class CognitoUserPoolTokens( - val idToken: String?, - val accessToken: String?, - val refreshToken: String?, - val expiration: Long? -) { - override fun toString(): String = "CognitoUserPoolTokens(" + - "idToken = ${idToken?.substring(0..4)}***, " + - "accessToken = ${accessToken?.substring(0..4)}***, " + - "refreshToken = ${refreshToken?.substring(0..4)}***" + - ")" - - override fun equals(other: Any?): Boolean = if (super.equals(other)) { - true - } else if (other == null || javaClass != other.javaClass || other !is CognitoUserPoolTokens) { - false - } else { - idToken == other.idToken && accessToken == other.accessToken && refreshToken == other.refreshToken - } -} - /** * Contains AWS credentials that allows access to AWS resources * @param accessKeyId access key id @@ -134,9 +106,9 @@ internal data class AWSCredentials( } override fun toString(): String = "AWSCredentials(" + - "accessKeyId = ${accessKeyId?.substring(0..4)}***, " + - "secretAccessKey = ${secretAccessKey?.substring(0..4)}***, " + - "sessionToken = ${sessionToken?.substring(0..4)}***, " + + "accessKeyId = ${accessKeyId.mask()}, " + + "secretAccessKey = ${secretAccessKey.mask()}, " + + "sessionToken = ${sessionToken.mask()}, " + "expiration = $expiration" + ")" } diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/LoginsMapProvider.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/LoginsMapProvider.kt index d8779e4742..92e1e49bb8 100644 --- a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/LoginsMapProvider.kt +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/LoginsMapProvider.kt @@ -21,7 +21,7 @@ internal sealed class LoginsMapProvider { data class CognitoUserPoolLogins( private val region: String? = "", private val poolId: String? = "", - private val idToken: String + private val idToken: IdToken ) : LoginsMapProvider() { /** @@ -30,7 +30,7 @@ internal sealed class LoginsMapProvider { */ val providerName = "cognito-idp.$region.amazonaws.com/$poolId" - override val logins = mapOf(providerName to idToken) + override val logins = mapOf(providerName to idToken.tokenValue) } data class AuthProviderLogins(private val federatedToken: FederatedToken) : LoginsMapProvider() { diff --git a/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/Tokens.kt b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/Tokens.kt new file mode 100644 index 0000000000..60d5561118 --- /dev/null +++ b/aws-auth-cognito/src/main/java/com/amplifyframework/statemachine/codegen/data/Tokens.kt @@ -0,0 +1,139 @@ +/* + * Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amplifyframework.statemachine.codegen.data + +import android.util.Base64 +import com.amplifyframework.auth.exceptions.UnknownException +import com.amplifyframework.statemachine.util.mask +import java.time.Instant +import kotlin.text.Charsets.UTF_8 +import kotlinx.serialization.Serializable +import org.json.JSONObject + +internal abstract class Jwt { + abstract val tokenValue: String + + override fun toString() = tokenValue.mask() + override fun hashCode() = tokenValue.hashCode() + override fun equals(other: Any?) = other is Jwt && this.tokenValue == other.tokenValue + + private val parts by lazy { + tokenValue.split(".").also { + if (it.size != JWT_PARTS) { + throw UnknownException("Not a JSON web token. Error in parsing JSON") + } + } + } + + private val payload by lazy { + try { + val payload = parts[PAYLOAD] + val sectionDecoded = Base64.decode(payload, Base64.URL_SAFE) + val jwtSection = String(sectionDecoded, UTF_8) + JSONObject(jwtSection) + } catch (e: Exception) { + throw UnknownException("${e.localizedMessage ?: ""}, error in parsing JSON") + } + } + + protected fun getClaim(claim: Claim): String? = try { + if (payload.has(claim.key)) payload[claim.key].toString() else null + } catch (e: Exception) { + throw UnknownException("${e.localizedMessage ?: ""}, Invalid token") + } + + internal companion object { + private const val HEADER = 0 + private const val PAYLOAD = 1 + private const val SIGNATURE = 2 + private const val JWT_PARTS = 3 + } + + enum class Claim(val key: String) { + Expiration("exp"), + UserSub("sub"), + Username("username"), + TokenRevocationId("origin_jti") + } +} + +// See https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-id-token.html +@Serializable +internal class IdToken(override val tokenValue: String) : Jwt() { + val expiration: Instant? by lazy { + getClaim(Claim.Expiration)?.let { Instant.ofEpochSecond(it.toLong()) } + } +} + +// See https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-the-access-token.html +@Serializable +internal class AccessToken(override val tokenValue: String) : Jwt() { + val tokenRevocationId: String? + get() = getClaim(Claim.TokenRevocationId) + val userSub: String? + get() = getClaim(Claim.UserSub) + val username: String? + get() = getClaim(Claim.Username) + val expiration: Instant? by lazy { + getClaim(Claim.Expiration)?.let { Instant.ofEpochSecond(it.toLong()) } + } +} + +// Refresh token is just an opaque base64 string +@Serializable +@JvmInline +internal value class RefreshToken(val tokenValue: String) { + override fun toString() = tokenValue.mask() +} + +internal fun String?.asIdToken() = this?.let { IdToken(it) } +internal fun String?.asAccessToken() = this?.let { AccessToken(it) } +internal fun String?.asRefreshToken() = this?.let { RefreshToken(it) } + +/** + * Contains cognito user pool JWT tokens + * @param idToken User Pool id token + * @param accessToken User Pool access token + * @param refreshToken User Pool refresh token + * @param expiration Auth result expiration but not token expiration + */ +@Serializable +internal data class CognitoUserPoolTokens( + val idToken: IdToken?, + val accessToken: AccessToken?, + val refreshToken: RefreshToken?, + val expiration: Long? +) { + constructor( + idToken: String?, + accessToken: String?, + refreshToken: String?, + expiration: Long? + ) : this( + idToken = idToken.asIdToken(), + accessToken = accessToken.asAccessToken(), + refreshToken = refreshToken.asRefreshToken(), + expiration = expiration + ) + + override fun equals(other: Any?): Boolean = if (super.equals(other)) { + true + } else if (other == null || javaClass != other.javaClass || other !is CognitoUserPoolTokens) { + false + } else { + idToken == other.idToken && accessToken == other.accessToken && refreshToken == other.refreshToken + } +} diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/MockData.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/MockData.kt index 7abf1dda77..5edebc48ce 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/MockData.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/MockData.kt @@ -63,7 +63,7 @@ internal fun mockSignedInData( signedInDate: Date = Date(), signInMethod: SignInMethod = SignInMethod.ApiBased(SignInMethod.ApiBased.AuthType.USER_SRP_AUTH), cognitoUserPoolTokens: CognitoUserPoolTokens = - CognitoUserPoolTokens(idToken = null, accessToken = null, refreshToken = null, expiration = null) + CognitoUserPoolTokens(idToken = null as String?, accessToken = null, refreshToken = null, expiration = null) ) = SignedInData( userId = userId, username = username, diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/actions/FetchAuthSessionCognitoActionsTest.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/actions/FetchAuthSessionCognitoActionsTest.kt index 6c87c190b2..468d4adfdd 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/actions/FetchAuthSessionCognitoActionsTest.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/actions/FetchAuthSessionCognitoActionsTest.kt @@ -127,7 +127,7 @@ class FetchAuthSessionCognitoActionsTest { val event = capturedEvent.captured.shouldBeInstanceOf() val refreshedData = event.eventType.shouldBeInstanceOf().signedInData - refreshedData.cognitoUserPoolTokens.refreshToken shouldBe newRefreshToken + refreshedData.cognitoUserPoolTokens.refreshToken?.tokenValue shouldBe newRefreshToken } @Test @@ -164,7 +164,7 @@ class FetchAuthSessionCognitoActionsTest { val event = capturedEvent.captured.shouldBeInstanceOf() val refreshedData = event.eventType.shouldBeInstanceOf().signedInData - refreshedData.cognitoUserPoolTokens.refreshToken shouldBe originalRefreshToken + refreshedData.cognitoUserPoolTokens.refreshToken?.tokenValue shouldBe originalRefreshToken } @Test diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/data/TokensTest.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/data/TokensTest.kt new file mode 100644 index 0000000000..01bca8a2dd --- /dev/null +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/data/TokensTest.kt @@ -0,0 +1,92 @@ +/* + * Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.amplifyframework.auth.cognito.data + +import com.amplifyframework.statemachine.codegen.data.CognitoUserPoolTokens +import com.amplifyframework.statemachine.codegen.data.asAccessToken +import com.amplifyframework.statemachine.codegen.data.asIdToken +import com.amplifyframework.statemachine.codegen.data.asRefreshToken +import io.kotest.matchers.shouldBe +import java.time.Instant +import org.junit.Test + +class TokensTest { + private val tokenString = + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwidXNlcm5hbWUiOiJqZG" + + "9lIiwiaWF0IjoxNzU2OTk4Mjc4LCJleHAiOjE3NTY5OTg1NzgsIm9yaWdpbl9qdGkiOiJhYWFhYWFhYS1iYmJiLWNjY2MtZGRkZC1lZ" + + "WVlZWVlZWVlZWUifQ.3Mvd5WVi1z1GpQ37hEoev6DzYNv9lWNL-fGfQTxUYx4" + + @Test + fun `identity token returns expiry`() { + val token = tokenString.asIdToken() + token?.expiration shouldBe Instant.ofEpochSecond(1756998578) + } + + @Test + fun `access token returns expiry`() { + val token = tokenString.asAccessToken() + token?.expiration shouldBe Instant.ofEpochSecond(1756998578) + } + + @Test + fun `access token returns username`() { + val token = tokenString.asAccessToken() + token?.username shouldBe "jdoe" + } + + @Test + fun `access token returns userId`() { + val token = tokenString.asAccessToken() + token?.userSub shouldBe "1234567890" + } + + @Test + fun `access token returns revocationId`() { + val token = tokenString.asAccessToken() + token?.tokenRevocationId shouldBe "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" + } + + @Test + fun `id token string value is masked`() { + val idToken = tokenString.asIdToken() + idToken.toString() shouldBe "eyJh***" + } + + @Test + fun `access token string value is masked`() { + val accessToken = tokenString.asAccessToken() + accessToken.toString() shouldBe "eyJh***" + } + + @Test + fun `refresh token string value is masked`() { + val refreshToken = tokenString.asRefreshToken() + refreshToken.toString() shouldBe "eyJh***" + } + + @Test + fun `cognito tokens string value is masked`() { + val cognitoTokens = CognitoUserPoolTokens( + idToken = tokenString, + accessToken = tokenString, + refreshToken = tokenString, + expiration = null + ) + cognitoTokens.toString() shouldBe + "CognitoUserPoolTokens(idToken=eyJh***, accessToken=eyJh***, " + + "refreshToken=eyJh***, expiration=null)" + } +} diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/authstategenerators/AuthStateJsonGenerator.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/authstategenerators/AuthStateJsonGenerator.kt index add4411d35..ea887d8366 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/authstategenerators/AuthStateJsonGenerator.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/featuretest/generators/authstategenerators/AuthStateJsonGenerator.kt @@ -42,7 +42,7 @@ import java.util.Date * */ object AuthStateJsonGenerator : SerializableProvider { - const val DUMMY_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1l" + + val DUMMY_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1l" + "IiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" const val DUMMY_TOKEN_2 = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1l" + diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/helpers/JWTParserTests.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/helpers/JWTParserTests.kt deleted file mode 100644 index e69e1c5958..0000000000 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/helpers/JWTParserTests.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package com.amplifyframework.auth.cognito.helpers - -import com.amplifyframework.auth.AuthException -import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertTrue -import org.junit.Test - -class JWTParserTests { - - private val dummyHeader = "{\"typ\":\"JWT\",\"alg\":\"HS256\"}" - private val dummyPayload = "{\"sub\":\"1234567890\",\"name\":\"John Doe\",\"iat\":1516239022}" - private val dummyToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4g" + - "RG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.XbPfbIHMI6arZ3Y922BhjWgQzWXcXNrz0ogtVhfEd2o" - - @Test - fun testGetClaim() { - val sub = JWTParser.getClaim(dummyToken, "sub") - assertEquals("1234567890", sub) - } - - @Test - fun testGetHeader() { - val header = JWTParser.getHeader(dummyToken).toString() - assertEquals(dummyHeader, header) - } - - @Test - fun testGetPayload() { - val payload = JWTParser.getPayload(dummyToken).toString() - assertEquals(dummyPayload, payload) - } - - @Test - fun testHasClaim() { - val hasName = JWTParser.hasClaim(dummyToken, "name") - assertTrue(hasName) - } - - @Test - fun testHasClaimFail() { - val hasExpiry = JWTParser.hasClaim(dummyToken, "expiry") - assertFalse(hasExpiry) - } - - @Test(expected = AuthException::class) - fun testInvalidJWT() { - val invalidToken = "xxxxxx.yyyyyy" - JWTParser.validateJWT(invalidToken) - } -} diff --git a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/helpers/SessionHelperTests.kt b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/helpers/SessionHelperTests.kt index d42e3f55d2..5539bc0efb 100644 --- a/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/helpers/SessionHelperTests.kt +++ b/aws-auth-cognito/src/test/java/com/amplifyframework/auth/cognito/helpers/SessionHelperTests.kt @@ -19,7 +19,6 @@ import com.amplifyframework.statemachine.codegen.data.AWSCredentials import com.amplifyframework.statemachine.codegen.data.CognitoUserPoolTokens import java.time.Instant import java.time.temporal.ChronoUnit -import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue import org.junit.Test @@ -36,19 +35,6 @@ class SessionHelperTests { expiration = 0 ) - @Test - fun testGetExpiration() { - val expiry = SessionHelper.getExpiration(dummyToken) - val expected = Instant.parse("2018-01-18T01:30:22Z") - assertEquals(expected, expiry) - } - - @Test - fun testGetUsername() { - val username = dummyUserPoolTokens.accessToken?.let(SessionHelper::getUsername) - assertEquals("John Doe", username) - } - @Test fun testIsInvalid() { assertFalse(SessionHelper.isValidTokens(dummyUserPoolTokens)) @@ -56,7 +42,7 @@ class SessionHelperTests { @Test fun testIsInvalidNullTokens() { - assertFalse(SessionHelper.isValidTokens(CognitoUserPoolTokens(null, null, null, 0))) + assertFalse(SessionHelper.isValidTokens(CognitoUserPoolTokens(null as String?, null, null, 0))) } @Test diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_SessionEstablished.json b/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_SessionEstablished.json index c0ade06825..574fb257b8 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_SessionEstablished.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_SessionEstablished.json @@ -11,8 +11,12 @@ "authType": "USER_SRP_AUTH" }, "cognitoUserPoolTokens": { - "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "idToken": { + "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, + "accessToken": { + "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", "expiration": 300 } @@ -31,8 +35,12 @@ "authType": "USER_SRP_AUTH" }, "cognitoUserPoolTokens": { - "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "idToken": { + "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, + "accessToken": { + "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", "expiration": 300 } diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_SessionEstablished_User_Auth.json b/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_SessionEstablished_User_Auth.json index 7dffd662a8..697273f882 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_SessionEstablished_User_Auth.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_SessionEstablished_User_Auth.json @@ -11,8 +11,12 @@ "authType": "USER_AUTH" }, "cognitoUserPoolTokens": { - "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "idToken": { + "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, + "accessToken": { + "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", "expiration": 300 } @@ -31,8 +35,12 @@ "authType": "USER_AUTH" }, "cognitoUserPoolTokens": { - "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "idToken": { + "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, + "accessToken": { + "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", "expiration": 300 } diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json b/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json index 93bbd31c57..c9fd726ecc 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SignedIn_UserPoolSessionEstablished.json @@ -11,8 +11,12 @@ "authType": "USER_SRP_AUTH" }, "cognitoUserPoolTokens": { - "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "idToken": { + "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, + "accessToken": { + "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", "expiration": 300 } @@ -31,8 +35,12 @@ "authType": "USER_SRP_AUTH" }, "cognitoUserPoolTokens": { - "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "idToken": { + "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, + "accessToken": { + "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", "expiration": 300 } diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json b/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json index 028d2d4bd1..25d67e471e 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_IdentityPoolConfigured.json @@ -11,8 +11,12 @@ "authType": "USER_SRP_AUTH" }, "cognitoUserPoolTokens": { - "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "idToken": { + "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, + "accessToken": { + "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", "expiration": 300 } diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_SessionEstablished_AwaitingUserConfirmation.json b/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_SessionEstablished_AwaitingUserConfirmation.json index 5231e313d5..096ee1e66d 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_SessionEstablished_AwaitingUserConfirmation.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_SessionEstablished_AwaitingUserConfirmation.json @@ -19,8 +19,12 @@ "authType": "USER_SRP_AUTH" }, "cognitoUserPoolTokens": { - "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "idToken": { + "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, + "accessToken": { + "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", "expiration": 300 } diff --git a/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_SessionEstablished_SignedUp.json b/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_SessionEstablished_SignedUp.json index 67a379aafe..c286295496 100644 --- a/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_SessionEstablished_SignedUp.json +++ b/aws-auth-cognito/src/test/resources/feature-test/states/SignedOut_SessionEstablished_SignedUp.json @@ -19,8 +19,12 @@ "authType": "USER_SRP_AUTH" }, "cognitoUserPoolTokens": { - "idToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", - "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", + "idToken": { + "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, + "accessToken": { + "tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU" + }, "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VySWQiLCJ1c2VybmFtZSI6InVzZXJuYW1lIiwiZXhwIjoxNTE2MjM5MDIyLCJvcmlnaW5fanRpIjoib3JpZ2luX2p0aSJ9.Xqa-vjJe5wwwsqeRAdHf8kTBn_rYSkDn2lB7xj9Z1xU", "expiration": 300 } diff --git a/aws-datastore/src/androidTest/java/com/amplifyframework/datastore/MultiAuthSyncEngineNoAuthInstrumentationTest.java b/aws-datastore/src/androidTest/java/com/amplifyframework/datastore/MultiAuthSyncEngineNoAuthInstrumentationTest.java index 592bd8785a..443ce8f688 100644 --- a/aws-datastore/src/androidTest/java/com/amplifyframework/datastore/MultiAuthSyncEngineNoAuthInstrumentationTest.java +++ b/aws-datastore/src/androidTest/java/com/amplifyframework/datastore/MultiAuthSyncEngineNoAuthInstrumentationTest.java @@ -24,7 +24,7 @@ import com.amplifyframework.api.aws.AWSApiPlugin; import com.amplifyframework.api.aws.AuthModeStrategyType; import com.amplifyframework.api.aws.AuthorizationType; -import com.amplifyframework.auth.cognito.helpers.JWTParser; +import com.amplifyframework.api.aws.auth.CognitoJWTParser; import com.amplifyframework.core.Amplify; import com.amplifyframework.core.AmplifyConfiguration; import com.amplifyframework.core.category.CategoryConfiguration; @@ -223,7 +223,7 @@ private static AuthorizationType getRequestAuthType(Headers headers) { if (authHeaderValue.startsWith("AWS4-HMAC-SHA256")) { return AuthorizationType.AWS_IAM; } - String iss = JWTParser.INSTANCE.getClaim(authHeaderValue, "iss"); + String iss = CognitoJWTParser.Companion.getClaim(authHeaderValue, "iss"); if (iss == null) { throw new IllegalStateException("Could not find any valid auth headers"); }