Autenticación y autorización
Explore estrategias para autenticar clientes y autorizar el acceso a los métodos de los servicios gRPC.
Autenticación y autorización es una lección gratuita de gRPC & High Performance APIs en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de gRPC & High Performance APIs, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de gRPC & High Performance APIs incluye 4 lecciones en total.
Partes de esta lección aún no han sido traducidas y se muestran en inglés.
Secure Your gRPC Services
Welcome! In this lesson, we'll dive into Authentication and Authorization for gRPC services. These are crucial concepts for building secure and reliable distributed systems.
You'll learn how to verify who is accessing your services and what actions they are allowed to perform.
Authentication: Who Are You?
Authentication is the process of verifying a client's identity. Think of it like checking an ID at a club.
- It answers the question: "Are you who you say you are?"
- Common methods include API keys, JWTs (JSON Web Tokens), or OAuth tokens.
- In gRPC, these credentials are often passed as custom metadata with each request.
Authorization: What Can You Do?
Once a client is authenticated, Authorization determines what actions they are permitted to perform.
- It answers the question: "Are you allowed to do that?"
- For example, an "admin" user might be authorized to delete data, while a "guest" user can only view it.
- Authorization checks happen after successful authentication.
Why Auth & AuthZ Matter
Securing your gRPC services with proper authentication and authorization is vital:
- Prevent Unauthorized Access: Only trusted clients can interact with your services.
- Protect Sensitive Data: Ensure data is only accessed or modified by authorized entities.
- Compliance & Auditing: Meet regulatory requirements and maintain an audit trail of actions.
It's a foundational layer of security for any production system.
Clients Send Credentials
In gRPC, clients typically send authentication credentials as custom metadata in the request header.
This metadata is essentially a map of key-value pairs that travels with the RPC call. For instance, an API-Key or an Authorization header carrying a token.
The server then extracts and validates these credentials.
Server Verifies Identity
On the server side, your gRPC service needs logic to:
- Extract Credentials: Read the authentication token or API key from the incoming request's metadata.
- Validate Credentials: Check if the extracted credential is valid (e.g., compare an API key against a database, verify a JWT's signature and expiry).
- Identify Principal: If valid, identify the user or service making the request.
This process determines if the client is legitimate.
Server Checks Permissions
After a client is authenticated, the server proceeds to authorization.
This involves checking if the authenticated client (or "principal") has the necessary permissions to call the specific gRPC method requested.
- You might use roles (e.g.,
admin,user) or specific permissions associated with the client's identity. - This check often happens early in the method's execution or via an interceptor.
Attaching an API Key (Client)
Here's a simple Java client example that attaches an API-Key to a gRPC request using metadata. The Metadata class is used to build these headers.
Try running this example (you'll need the server from the next scene running first):
// auth_service.proto (simplified for context in code)
// syntax = "proto3";
// option java_multiple_files = true;
// option java_package = "com.coddykit.grpc.auth";
// option java_outer_classname = "AuthServiceProto";
// package auth;
// service AuthService {
// rpc SayHello (HelloRequest) returns (HelloResponse);
// rpc SayAdminHello (HelloRequest) returns (HelloResponse);
// }
// message HelloRequest { string name = 1; }
// message HelloResponse { string message = 1; }
package com.coddykit.grpc.auth;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;
import io.grpc.stub.StreamObserver;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class AuthClient {
private final ManagedChannel channel;
private final AuthServiceGrpc.AuthServiceStub asyncStub;
public AuthClient(String host, int port) {
channel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext() // For demonstration, use TLS in production
.build();
asyncStub = AuthServiceGrpc.newStub(channel);
}
public void shutdown() throws InterruptedException {
channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
}
public void callServiceWithKey(String method, String name, String apiKey) throws InterruptedException {
System.out.println("--- Calling " + method + " with API Key: " + apiKey + " ---");
final CountDownLatch latch = new CountDownLatch(1);
Metadata headers = new Metadata();
Metadata.Key<String> apiKeyHeader = Metadata.Key.of("api-key", Metadata.ASCII_STRING_MARSHALLER);
headers.put(apiKeyHeader, apiKey);
AuthServiceGrpc.AuthServiceStub authenticatedStub = MetadataUtils.attachHeaders(asyncStub, headers);
HelloRequest request = HelloRequest.newBuilder().setName(name).build();
StreamObserver<HelloResponse> responseObserver = new StreamObserver<HelloResponse>() {
@Override
public void onNext(HelloResponse response) {
System.out.println("Response: " + response.getMessage());
}
@Override
public void onError(Throwable t) {
System.err.println("Error calling " + method + ": " + t.getMessage());
latch.countDown();
}
@Override
public void onCompleted() {
System.out.println("Call completed.");
latch.countDown();
}
};
if ("SayHello".equals(method)) {
authenticatedStub.sayHello(request, responseObserver);
} else if ("SayAdminHello".equals(method)) {
authenticatedStub.sayAdminHello(request, responseObserver);
} else {
System.err.println("Unknown method: " + method);
latch.countDown();
}
latch.await(1, TimeUnit.MINUTES);
}
public static void main(String[] args) throws Exception {
AuthClient client = new AuthClient("localhost", 50051);
try {
// These keys would be issued to different clients
String validApiKey = "my-secret-api-key-123";
String adminApiKey = "admin-secret-key-456";
String invalidApiKey = "wrong-key";
client.callServiceWithKey("SayHello", "Alice", validApiKey);
Thread.sleep(500);
client.callServiceWithKey("SayHello", "Bob", invalidApiKey);
Thread.sleep(500);
client.callServiceWithKey("SayAdminHello", "Charlie", validApiKey);
Thread.sleep(500);
client.callServiceWithKey("SayAdminHello", "AdminUser", adminApiKey);
Thread.sleep(500);
} finally {
client.shutdown();
}
}
}Validating API Key (Server)
This server example demonstrates how an interceptor extracts the API-Key from the request metadata and performs initial authentication. If valid, the key is attached to the Context.
Service methods then retrieve the key from the Context for fine-grained authorization checks. This is a common and robust pattern.
Try running this example (start this server, then the client from the previous scene):
// auth_service.proto (simplified for context in code)
// syntax = "proto3";
// option java_multiple_files = true;
// option java_package = "com.coddykit.grpc.auth";
// option java_outer_classname = "AuthServiceProto";
// package auth;
// service AuthService {
// rpc SayHello (HelloRequest) returns (HelloResponse);
// rpc SayAdminHello (HelloRequest) returns (HelloResponse);
// }
// message HelloRequest { string name = 1; }
// message HelloResponse { string message = 1; }
package com.coddykit.grpc.auth;
import io.grpc.Context;
import io.grpc.Metadata;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.ServerCall;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;
import io.grpc.Status;
import io.grpc.stub.StreamObserver;
import java.io.IOException;
import java.util.logging.Logger;
public class AuthServer {
private static final Logger logger = Logger.getLogger(AuthServer.class.getName());
private Server server;
private void start() throws IOException {
int port = 50051;
server = ServerBuilder.forPort(port)
.addService(new AuthServiceImpl())
.intercept(new AuthInterceptor()) // Add our authentication interceptor
.build()
.start();
logger.info("Server started, listening on " + port);
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.err.println("*** shutting down gRPC server since JVM is shutting down");
try {
AuthServer.this.stop();
} catch (InterruptedException e) {
e.printStackTrace(System.err);
}
System.err.println("*** server shut down");
}));
}
private void stop() throws InterruptedException {
if (server != null) {
server.shutdown().awaitTermination(30, java.util.concurrent.TimeUnit.SECONDS);
}
}
private void blockUntilShutdown() throws InterruptedException {
if (server != null) {
server.awaitTermination();
}
}
public static void main(String[] args) throws IOException, InterruptedException {
final AuthServer server = new AuthServer();
server.start();
server.blockUntilShutdown();
}
// Context key to store the authenticated API Key after interceptor processing
static final Context.Key<String> AUTH_API_KEY = Context.key("api-key");
// A simple, hardcoded valid API key for demonstration
private static final String VALID_API_KEY = "my-secret-api-key-123";
private static final String ADMIN_API_KEY = "admin-secret-key-456"; // For authorization example
static class AuthInterceptor implements ServerInterceptor {
static final Metadata.Key<String> API_KEY_METADATA_KEY =
Metadata.Key.of("api-key", Metadata.ASCII_STRING_MARSHALLER);
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT, RespT> call,
Metadata headers,
ServerCallHandler<ReqT, RespT> next) {
String apiKey = headers.get(API_KEY_METADATA_KEY);
// Basic Authentication check in the interceptor
if (apiKey == null || (!apiKey.equals(VALID_API_KEY) && !apiKey.equals(ADMIN_API_KEY))) {
logger.warning("AuthInterceptor: Authentication failed - Invalid or missing API key.");
call.close(Status.UNAUTHENTICATED.withDescription("Missing or invalid API key"), headers);
return new ServerCall.Listener<ReqT>() {}; // No-op listener
}
// If authenticated, attach the API key to the Context for later use by service methods
Context context = Context.current().withValue(AUTH_API_KEY, apiKey);
return Context.current().call(() -> next.startCall(call, headers));
}
}
static class AuthServiceImpl extends AuthServiceGrpc.AuthServiceImplBase {
@Override
public void sayHello(HelloRequest request, StreamObserver<HelloResponse> responseObserver) {
String apiKey = AUTH_API_KEY.get(); // Get API key from Context (set by interceptor)
logger.info("AuthServiceImpl: sayHello called with authenticated API Key: " + apiKey);
// No further authorization needed for SayHello, as authentication was done by interceptor
String message = "Hello " + request.getName() + " from authenticated service!";
HelloResponse response = HelloResponse.newBuilder().setMessage(message).build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
@Override
public void sayAdminHello(HelloRequest request, StreamObserver<HelloResponse> responseObserver) {
String apiKey = AUTH_API_KEY.get(); // Get API key from Context (set by interceptor)
// Authorization check (only admin key can access this specific method)
if (!apiKey.equals(ADMIN_API_KEY)) {
logger.warning("AuthServiceImpl: Authorization failed - API key " + apiKey + " is not authorized for admin access.");
responseObserver.onError(
Status.PERMISSION_DENIED
.withDescription("Access denied: Requires admin privileges")
.asRuntimeException());
return;
}
logger.info("AuthServiceImpl: sayAdminHello called with authorized API Key: " + apiKey);
String message = "Hello Admin " + request.getName() + " from secure service!";
HelloResponse response = HelloResponse.newBuilder().setMessage(message).build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
}
}Check Your Understanding
Time for a quick check!
Recap: Auth & AuthZ
Great job! In this lesson, we explored:
- The difference between Authentication (who you are) and Authorization (what you can do).
- How clients send credentials via gRPC metadata.
- How servers can extract these credentials and apply both authentication and authorization logic, often with the help of interceptors.
Securing your gRPC services is a critical step towards building robust and reliable distributed applications!
Preguntas frecuentes
¿La lección «Autenticación y autorización» es gratis?
Sí — el texto completo de «Autenticación y autorización» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de gRPC & High Performance APIs, actualiza a CoddyKit PRO. El curso de gRPC & High Performance APIs incluye 4 lecciones en total.
¿Qué aprenderé en «Autenticación y autorización»?
Explore estrategias para autenticar clientes y autorizar el acceso a los métodos de los servicios gRPC. Practicas gRPC & High Performance APIs con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar gRPC & High Performance APIs?
No se requiere experiencia previa. gRPC & High Performance APIs en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.
¿Cuánto tiempo toma la lección «Autenticación y autorización»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de gRPC & High Performance APIs?
Sí. Cada lección de gRPC & High Performance APIs incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- TLS/SSL para gRPC
- Autenticación y autorización
- Interceptores para la seguridad
- TLS mutuo (mTLS) para la autenticación entre servicios