-
Notifications
You must be signed in to change notification settings - Fork 578
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Route header classes #4562
base: auth-exchange
Are you sure you want to change the base?
Add Route header classes #4562
Conversation
Coverage Report 1Affected Products
Test Logs |
Size Report 1Affected Products
Test Logs |
@@ -0,0 +1,53 @@ | |||
plugins { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing copyright notice here and elsewhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! I had a script I wrote that would automatically add it to any missing files, but it doesn't auto-run. We should probably have some sort of check regarding that. Not anything that's enforced, since there are way too many exceptions, but maybe like a git hook or gha that looks at files added and lets you know if any of interest are missing copyright notices (.kt
,.java
,etc.,).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is one, and it's correctly reporting this :-)
https://github.com/firebase/firebase-android-sdk/actions/runs/3917153439
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LOL, well I'll be paying more attention to that one for sure
firebase-authexchange/src/main/kotlin/com/google/firebase/authexchange/network/Routes.kt
Show resolved
Hide resolved
* | ||
* @property idToken JWT encoded OIDC token returned from a third party provider | ||
*/ | ||
@Serializable internal data class ImplicitCredentialsP(val idToken: String) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does the P
suffix stand for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Protobuf, implying that these data classes are representations of gRPC related data (that is, they're raw classes that shouldn't be used directly, and are intended to only be used by the network layer). I'm not quite sure where I picked this up from, but I've used this naming convention by habit in all of my personal gRPC projects. Helps more easily difference between the network and application layer.
Although if you're against it, I'm fine with removing it:)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to be consistent with the rest of our code, I'd rathe remove it.
That being said, the discussion of the value and usage of suffixes in code naming is a long and interesting one for the future :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to removing the P
suffix. If you really want to add a suffix for clarity, perhaps just fully putting Proto
instead? Unless the P
shortening is a Kotlin convention.
firebase-authexchange/src/main/kotlin/com/google/firebase/authexchange/network/Routes.kt
Outdated
Show resolved
Hide resolved
* OIDC Credential. | ||
* | ||
* Useful for apps with external login already set-up, otherwise known as a headless OIDC flow. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is an OIDC credential, would it make sense to call the class that? Not sure if implicit credentials is the right naming.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would be comfortable with that, although the property name would still be implicitCredentials
in the API call, because that's what the API expects.
I can't link it here since it's an internal link- but if you look at the bug linked in this PR (referenced in the OP), and go to the first link in the comments of that bug, you can see all the proto defs for the API. These definitions and their names are derived from that- since these are all just data classes for the API- intended to be encoded to JSON via @Serializable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I forgot we can specify a @SerialName
for encoding and decoding, so we would call it something else but it gets translated to implicitCredentials
when it's sent. But seeing as this is ONLY for the API, and shouldn't be used beyond that- I think it's totally fine keeping it as is. Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an scenario where more details help :-) You could change the first line of the description to "Credentials returned by an OIDC implicit flow" Then the name would sound more fitting. No need to use @SerialName
firebase-authexchange/src/main/kotlin/com/google/firebase/authexchange/network/Routes.kt
Outdated
Show resolved
Hide resolved
* This is merely the proto type for the network layer, and is completely separate from the user | ||
* facing [AuthExchangeToken][com.google.firebase.authexchange.AuthExchangeToken]. | ||
* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what do you mean by a proto type in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As in it's a data class used for communicating via protobuf APIs (the backend for auth echange). Although I do think the phrasing gives off the wrong impression. Thoughts on this instead:
* Not to be confused with [AuthExchangeToken][com.google.firebase.authexchange.AuthExchangeToken],
* this is intended only for network requests.
Or maybe just removing it entirely?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 your suggested rewording.
@Serializable internal data class AuthExchangeTokenP(val accessToken: String, val ttl: String) | ||
|
||
/** | ||
* Request header for the `/ExchangeInstallationAuthToken` endpoint. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a header or the actual request?
here and below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So nothing here actually implements the requests themselves. These are all just headers, or type defs, of what the API expects. Skeletons you could say. Actual implementation and utilization of these classes will be elsewhere in the SDK.
The API is currently defined in protobuf in G3, and all these classes provide a type-safe kotlin variant of the API as it is defined. Additionally, we can use kotlin's serialization, and immediately encode classes to JSON requests for the backend, and vise versa for JSON responses from the backend.
Just a little quick example (psuedo code):
data class GetPersonRequestP(val name: String)
data class GetPersonResponseP(val person: Person?, val error: String?)
data class Person(val name: String, age: Int, phoneNumber: String)
fun getPerson() {
val myQuery = GetPersonRequestP("Rodrigo")
val response: GetPersonResponseP = googleServer:GetRequest<GetPersonRequestP>(myQuery)
response?.person?.let {
println("Rodrigo is ${it.age} years old!")
}
}
All subclasses of Request
are definitions for what individual API endpoints expect in their request call.
All subclasses of Response
are definitions for what API endpoints return in their response to request calls.
Anything else is just extra data types that either need to be arguments in a call to a certain API, or are apart of a response.
Does that answer your question? Or did I misunderstand what you were asking?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All below are either Request
or Response
subclasses, and they are named as such, but the doc says "headers" which is different. A header is metadata about the request, but these classes contain the actual content of the requests/responses.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All below are either
Request
orResponse
subclasses, and they are named as such, but the doc says "headers" which is different. A header is metadata about the request, but these classes contain the actual content of the requests/responses.
They contain the content sure, but only in the sense that it's a data class and doesn't have any content. I think C headers- where data types and function signatures are declared in header files, and the source file implements said methods.
Although, what do you think would be a better name? We could also always just split it up into two separate files; request.kt
and response.kt
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to "request header" implying network request headers, for example the x-firebase-appcheck
header.
Though I'm not sure I understand what you mean when you say the actual implementation of these classes will exist elsewhere -- from my understanding of a Kotlin data class, it is essentially like a struct, which is fully instantiable (i.e. it's not like a Java interface where you need to implement the interface before it can be used). Also, are these data classes not implementations of the Request
interface already?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from my understanding of a Kotlin data class, it is essentially like a struct
You're right on the money
what you mean when you say the actual implementation of these classes
Implementation was probably the wrong phrasing, I more-so meant the usage of these classes occur elsewhere- and this isn't intended to provide any logic
Also, are these data classes not implementations of the Request interface already?
They are, I just meant splitting the files for naming & organization sake
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see -- in terms of naming clarity, I think you can just remove the term "header" from the documentation and leave the rest of the comment the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
* | ||
* @property idToken JWT encoded OIDC token returned from a third party provider | ||
*/ | ||
@Serializable internal data class ImplicitCredentialsP(val idToken: String) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to removing the P
suffix. If you really want to add a suffix for clarity, perhaps just fully putting Proto
instead? Unless the P
shortening is a Kotlin convention.
@Serializable internal data class AuthExchangeTokenP(val accessToken: String, val ttl: String) | ||
|
||
/** | ||
* Request header for the `/ExchangeInstallationAuthToken` endpoint. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to "request header" implying network request headers, for example the x-firebase-appcheck
header.
Though I'm not sure I understand what you mean when you say the actual implementation of these classes will exist elsewhere -- from my understanding of a Kotlin data class, it is essentially like a struct, which is fully instantiable (i.e. it's not like a Java interface where you need to implement the interface before it can be used). Also, are these data classes not implementations of the Request
interface already?
firebase-authexchange/src/main/kotlin/com/google/firebase/authexchange/network/Routes.kt
Show resolved
Hide resolved
internal data class ExchangeOidcTokenRequestP( | ||
val token: String, | ||
val providerId: String, | ||
val implicitCredentials: ImplicitCredentialsP |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ExchangeOidcTokenRequest
can take either implicit credentials or auth code credentials (see the API proto). Is there a way to represent this as a oneof
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For sure, although do we use it on our end? I initially had the following comment:
/**
* While this isn't the only OIDC flow that the API supports, it's the only flow that the mobile SDK
* supports- so there is no base class for credentials.
*/
Because I was under the impression we don't utilize AuthCodeCredentials
on the SDK?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The auth code OIDC flow is the "headful" flow (detailed here).
*/ | ||
@Serializable | ||
internal data class ExchangeInstallationAuthTokenRequestP( | ||
val token: String, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The token
field is unnecessary as part of the request object (here and in all the requests). In the backend, the token
field is extracted from the request URL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ahh I see. Is it the key
param, or is it actually called token
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean by key
param? For additional context -- here is the request path. Note the token=
portion of the request path -- that is where the token
field is populated from.
friendly ping |
Per b/265455809,
This adds data class headers for the
FirebaseAuthExchange
backend API routes. Each route follows the proto definition as defined by the API, with nearly identical naming conventions, and proper documentation across the board.Additionally, this PR refactors the groovy build file to kotlin- to be more align with future plans.
firebase-authexchange-interop
's build file is still in groovy, and will be addressed down the line as needed.