Skip to content
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

feat: implement authenticateRequest and verifyToken helper methods #31

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

2ynn
Copy link

@2ynn 2ynn commented Oct 10, 2024

This PR implements authenticateRequest and verifyToken helper methods.

Notes

  • the src/main/java/com/clerk/backend_api/helpers/ folder is .genignored
  • unlike in the clerk-sdk-python implementation, the secretKey should be passed manually. Due to sdkConfiguration being a private member of Clerk class, the bearerAuth value passed during sdk instantiation cannot be reused as secretKey for convenience.

Limitations

  • the added helper functions are only applicable for Backend APIs, afterSignInUrl/afterSignUpUrl options are not implemented
  • multi-domain setup (isSatellite, proxyUrl, signInUrl, signUpUrl) is not implemented
  • caching is not covered by this PR and skipJwksCache option is not made available

Tests

To run tests (./gradlew test) the following environment variables should be set:

  • CLERK_SESSION_TOKEN: The session token to be tested.
  • CLERK_SECRET_KEY: The Clerk secret key from the API Keys page in the Clerk Dashboard (needed for fetching Clerk's Jwks)
  • CLERK_JWT_KEY: The PEM public key from Clerk Dashboard (needed for networkless verification only)

Example Usage

  1. Remote JWKS (using secretKey)
import java.net.http.HttpRequest;
import com.clerk.backend_api.helpers.jwks.AuthenticateRequest;
import com.clerk.backend_api.helpers.jwks.AuthenticateRequestOptions;
import com.clerk.backend_api.helpers.jwks.RequestState;

public class UserAuthentication {

    public static boolean isSignedIn(HttpRequest request) {
        RequestState state = AuthenticateRequest.authenticateRequest(request, AuthenticateRequestOptions
                .secretKey(System.getenv("CLERK_SECRET_KEY"))
                .authorizedParty("https://example.com")
                .build());
        return state.isSignedIn();
    }
  1. Networkless (using local PEM formatted jwtKey)
import java.net.http.HttpRequest;
import com.clerk.backend_api.helpers.jwks.AuthenticateRequest;
import com.clerk.backend_api.helpers.jwks.AuthenticateRequestOptions;
import com.clerk.backend_api.helpers.jwks.RequestState;

public class UserAuthentication {

   public static boolean isSignedIn(HttpRequest request) {
        RequestState state = AuthenticateRequest.authenticateRequest(request, AuthenticateRequestOptions
                .jwtKey(System.getenv("CLERK_JWT_KEY"))
                .authorizedParty("https://example.com")
                .build());
        return state.isSignedIn();
    }
}

@2ynn 2ynn marked this pull request as draft October 10, 2024 18:06
@2ynn 2ynn marked this pull request as ready for review October 10, 2024 18:55
Copy link

@alex-ntousias alex-ntousias left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, it looks good to me! I've added a few comments to be addressed.
Just to confirm, you've tested it and everything works as expected, right?

return new Builder();
}

public static BuilderWithKey secretKey(String secretKey) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file contains quite a lot of nested classes and it's difficult to follow.
I understand the intention of providing a builder pattern that ensures you start with either a secret key or a jwt. But, I believe there might be ways to simplify it.

For example, can we have a single builder inner class with a private constructor which exposes two static methods jwtKey and secretKey to return an instance of the builder?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two methods are now made available:

    public static Builder secretKey(String secretKey) {
        return Builder.withSecretKey(secretKey);
    }

    public static Builder jwtKey(String jwtKey) {
        return Builder.withJwtKey(jwtKey);
    }

let me know if I missed the mark

@2ynn 2ynn force-pushed the feat/add-authenticateRequest branch from 6c6e211 to ca0e29d Compare October 15, 2024 15:02
@2ynn 2ynn closed this Oct 15, 2024
@2ynn 2ynn reopened this Oct 15, 2024
@2ynn
Copy link
Author

2ynn commented Oct 15, 2024

Overall, it looks good to me! I've added a few comments to be addressed. Just to confirm, you've tested it and everything works as expected, right?

Thanks for the review @alex-ntousias !

To run tests locally I have:

  1. created an account and grabbed the secretKey (CLERK_SECRET_KEY)+ PEM public key (CLERK_JWT_KEY) from the dashboard
  2. created a barebone nextjs app that I ran on localhost:3000
  3. signed in using github
  4. retrieved the session cookie from the browser (CLERK_SESSION_TOKEN)
  5. ran ./gradlew test successfully
  6. ran tests again: tests still pass but throw warnings to indicate the token is expired.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants