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
/protectedendpoint. - 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/jwtpackage for JWT operations.
Expected Behavior:
/login(POST):- Accepts
usernameandpasswordin 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.
- Accepts
/protected(GET):- Requires a valid JWT in the
Authorizationheader (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.
- Requires a valid JWT in the
Edge Cases to Consider:
- Missing Authorization Header: The
/protectedendpoint should handle the case where theAuthorizationheader is missing. - Invalid JWT Format: The
/protectedendpoint should handle cases where the JWT is malformed. - Expired JWT: The
/protectedendpoint should handle cases where the JWT has expired. - Invalid Signature: The
/protectedendpoint should handle cases where the JWT signature is invalid. - Empty Username/Password: The
/loginendpoint 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
/loginendpoint expects JSON input. - Response Format: The
/loginendpoint returns a JSON response containing the token. The/protectedendpoint 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/jwtpackage for JWT creation and verification. - Consider using a library like
gorilla/muxfor routing, but it's not strictly required. You can use the standardnet/httppackage. - Remember to handle errors gracefully and return appropriate HTTP status codes.
- The
some_long_jwt_stringin 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.