Hone logo
Hone
Problems

Secure API with JWT Authentication in Go

This challenge focuses on implementing JSON Web Token (JWT) authentication in a Go API. JWTs are a standard for securely transmitting information between parties as a JSON object, often used for authentication and authorization. Successfully completing this challenge will allow you to build APIs that require user authentication and protect sensitive resources.

Problem Description

You are tasked with creating a simple Go API that utilizes JWTs for authentication. The API should have two endpoints: /login and /protected. The /login endpoint should accept a username and password, and upon successful authentication (for simplicity, assume any username/password combination is valid), it should generate a JWT and return it to the client. The /protected endpoint should require a valid JWT in the Authorization header. If a valid JWT is provided, the endpoint should return a success message. If no JWT is provided or the JWT is invalid, it should return an error.

Key Requirements:

  • JWT Generation: Implement JWT generation upon successful login. The JWT should contain a subject claim (e.g., the username) and an expiration time.
  • JWT Verification: Implement JWT verification in the /protected endpoint.
  • Error Handling: Handle cases where a JWT is missing or invalid, returning appropriate error responses.
  • Security: Use a strong secret key for signing the JWT. (For this exercise, you can hardcode it, but in a real application, this should be stored securely).
  • Standard Library: Utilize the standard crypto/jwt package for JWT operations.

Expected Behavior:

  • /login (POST):
    • Accepts username and password in the request body (JSON format).
    • Returns a JWT in the response body (JSON format) upon successful login.
    • Returns an error if the request body is invalid.
  • /protected (GET):
    • Requires a valid JWT in the Authorization header (e.g., Authorization: Bearer <JWT>).
    • Returns a success message ("Access granted!") if the JWT is valid.
    • Returns a 401 Unauthorized error if the JWT is missing or invalid.

Edge Cases to Consider:

  • Missing Authorization Header: The /protected endpoint should handle the case where the Authorization header is missing.
  • Invalid JWT Format: The /protected endpoint should handle cases where the JWT is malformed.
  • Expired JWT: The /protected endpoint should handle cases where the JWT has expired.
  • Invalid Signature: The /protected endpoint should handle cases where the JWT signature is invalid.
  • Empty Username/Password: The /login endpoint should handle empty username/password.

Examples

Example 1:

Input (POST /login):
{
  "username": "testuser",
  "password": "password123"
}
Output:
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN1c2VyIiwiaWF0IjoxNjk4NzQ4ODAwfQ.some_long_jwt_string"
}
Explanation: A JWT is generated and returned upon successful login with the provided username and password. The token contains the username as the subject and a timestamp.

Example 2:

Input (GET /protected):
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN1c2VyIiwiaWF0IjoxNjk4NzQ4ODAwfQ.some_long_jwt_string
Output:
"Access granted!"
Explanation: The request includes a valid JWT in the Authorization header, so access is granted.

Example 3:

Input (GET /protected):
Authorization: Invalid JWT
Output:
401 Unauthorized
Explanation: The JWT is invalid, so the server returns a 401 Unauthorized error.

Constraints

  • JWT Secret Key: The secret key used for signing the JWT should be at least 32 characters long.
  • Token Expiration: The JWT should expire within 1 hour of issuance.
  • Input Format: The /login endpoint expects JSON input.
  • Response Format: The /login endpoint returns a JSON response containing the token. The /protected endpoint returns a plain text string or a 401 error.
  • Performance: The solution should be reasonably efficient. Avoid unnecessary computations or allocations. This is a small API, so extreme optimization is not required.

Notes

  • Focus on the core JWT authentication logic. You don't need to implement user storage or password hashing for this challenge. Assume authentication is successful if a username and password are provided.
  • Use the crypto/jwt package for JWT creation and verification.
  • Consider using a library like gorilla/mux for routing, but it's not strictly required. You can use the standard net/http package.
  • Remember to handle errors gracefully and return appropriate HTTP status codes.
  • The some_long_jwt_string in the example is a placeholder. Your generated JWT will be different.
  • Pay close attention to the JWT claims and how they are used for verification.
Loading editor...
go