Skip to content

Commit

Permalink
Add support for getting OAuth token info (#205)
Browse files Browse the repository at this point in the history
# Description
This PR adds support for the /v3/connect/tokeninfo endpoint.

# Usage
There are two methods that are part of the `Auth` resource that allow
you to get information on a token; one for the ID token (`idTokenInfo`)
and one for the access token (`accessTokenInfo`).

```java
NylasClient nylas = new NylasClient.Builder("API_KEY").build();

// Get information on an ID token
Response<TokenInfoResponse> idTokenInfo = nylas.auth.idTokenInfo("idToken");

// Get information on an access token
Response<TokenInfoResponse> accessTokenInfo = nylas.auth.accessTokenInfo("accessToken");
```

# License
<!-- Your PR comment must contain the following line for us to merge the
PR. -->
I confirm that this contribution is made under the terms of the MIT
license and that I have the authority necessary to make this
contribution on behalf of its copyright owner.
  • Loading branch information
mrashed-dev authored Feb 9, 2024
1 parent 42cd063 commit 65b8977
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 1 deletion.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

## Unreleased

* Fix schema issue in the `Event`, `Message`, and `Draft` models
### Added

* Add support for getting OAuth token info

### Changed
* Fix schema issues in the `Event`, `Message`, `Draft`, and `CodeExchangeResponse` models

## [2.0.0] - Released 2024-02-05

Expand Down
5 changes: 5 additions & 0 deletions src/main/kotlin/com/nylas/models/CodeExchangeResponse.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ data class CodeExchangeResponse(
*/
@Json(name = "scope")
val scope: String,
/**
* Email address of the grant that is created.
*/
@Json(name = "email")
val email: String? = null,
/**
* Only returned if the code was requested using [AccessType.OFFLINE][com.nylas.models.AccessType.OFFLINE].
*/
Expand Down
20 changes: 20 additions & 0 deletions src/main/kotlin/com/nylas/models/TokenInfoRequest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.nylas.models

import com.squareup.moshi.Json

/**
* A request to query the information of a token.
* @suppress Used internally by the SDK
*/
data class TokenInfoRequest(
/**
* The ID token to query.
*/
@Json(name = "id_token")
val idToken: String? = null,
/**
* The access token to query.
*/
@Json(name = "access_token")
val accessToken: String? = null,
) : IQueryParams
36 changes: 36 additions & 0 deletions src/main/kotlin/com/nylas/models/TokenInfoResponse.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.nylas.models

import com.squareup.moshi.Json

data class TokenInfoResponse(
/**
* The issuer of the token.
*/
@Json(name = "iss")
val iss: String,
/**
* The token's audience.
*/
@Json(name = "aud")
val aud: String,
/**
* The time that the token was issued.
*/
@Json(name = "iat")
val iat: Int,
/**
* The time that the token expires.
*/
@Json(name = "exp")
val exp: Int,
/**
* The token's subject.
*/
@Json(name = "sub")
val sub: String? = null,
/**
* The email address of the Grant belonging to the user's token.
*/
@Json(name = "email")
val email: String? = null,
)
28 changes: 28 additions & 0 deletions src/main/kotlin/com/nylas/resources/Auth.kt
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,28 @@ class Auth(private val client: NylasClient) {
return client.executePost(path, responseType, queryParams = params)
}

/**
* Get info about an ID token
* @param idToken The ID token to query
* @return The token information
*/
@Throws(NylasApiError::class, NylasSdkTimeoutError::class)
fun idTokenInfo(idToken: String): Response<TokenInfoResponse> {
val params = TokenInfoRequest(idToken = idToken)
return getTokenInfo(params)
}

/**
* Get info about an access token
* @param accessToken The access token to query
* @return The token information
*/
@Throws(NylasApiError::class, NylasSdkTimeoutError::class)
fun accessTokenInfo(accessToken: String): Response<TokenInfoResponse> {
val params = TokenInfoRequest(accessToken = accessToken)
return getTokenInfo(params)
}

/**
* Hash a plain text secret for use in PKCE
* @param secret The plain text secret to hash
Expand Down Expand Up @@ -180,4 +202,10 @@ class Auth(private val client: NylasClient) {

return url
}

private fun getTokenInfo(params: TokenInfoRequest): Response<TokenInfoResponse> {
val path = "v3/connect/tokeninfo"
val responseType = Types.newParameterizedType(Response::class.java, TokenInfoResponse::class.java)
return client.executeGet(path, responseType, queryParams = params)
}
}
40 changes: 40 additions & 0 deletions src/test/kotlin/com/nylas/resources/AuthTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -318,5 +318,45 @@ class AuthTests {
assertNull(requestBodyCaptor.firstValue)
assertEquals(true, res)
}

@Test
fun `idTokenInfo calls requests with the correct params`() {
val idToken = "user-id-token"

auth.idTokenInfo(idToken)

val pathCaptor = argumentCaptor<String>()
val typeCaptor = argumentCaptor<Type>()
val queryParamCaptor = argumentCaptor<TokenInfoRequest>()
verify(mockNylasClient).executeGet<Response<TokenInfoResponse>>(
pathCaptor.capture(),
typeCaptor.capture(),
queryParamCaptor.capture(),
)

assertEquals("v3/connect/tokeninfo", pathCaptor.firstValue)
assertEquals(Types.newParameterizedType(Response::class.java, TokenInfoResponse::class.java), typeCaptor.firstValue)
assertEquals(TokenInfoRequest(idToken = idToken), queryParamCaptor.firstValue)
}

@Test
fun `accessTokenInfo calls requests with the correct params`() {
val accessToken = "nylas-access-token"

auth.accessTokenInfo(accessToken)

val pathCaptor = argumentCaptor<String>()
val typeCaptor = argumentCaptor<Type>()
val queryParamCaptor = argumentCaptor<TokenInfoRequest>()
verify(mockNylasClient).executeGet<Response<TokenInfoResponse>>(
pathCaptor.capture(),
typeCaptor.capture(),
queryParamCaptor.capture(),
)

assertEquals("v3/connect/tokeninfo", pathCaptor.firstValue)
assertEquals(Types.newParameterizedType(Response::class.java, TokenInfoResponse::class.java), typeCaptor.firstValue)
assertEquals(TokenInfoRequest(accessToken = accessToken), queryParamCaptor.firstValue)
}
}
}

0 comments on commit 65b8977

Please sign in to comment.