All Projects → johanbrandhorst → Grpc Auth Example

johanbrandhorst / Grpc Auth Example

Licence: mit
Examples of client authentication with gRPC

Programming Languages

go
31211 projects - #10 most used programming language

Projects that are alternatives of or similar to Grpc Auth Example

Pac4j
Security engine for Java (authentication, authorization, multi frameworks): OAuth, CAS, SAML, OpenID Connect, LDAP, JWT...
Stars: ✭ 2,097 (+3126.15%)
Mutual labels:  authentication, jwt, authorization
Charon
Authorization and authentication service.
Stars: ✭ 79 (+21.54%)
Mutual labels:  grpc, authentication, authorization
Awesome Iam
👤 Identity and Access Management Knowledge for Cloud Platforms
Stars: ✭ 186 (+186.15%)
Mutual labels:  authentication, jwt, authorization
Express Mongodb Rest Api Boilerplate
A boilerplate for Node.js apps / Rest API / Authentication from scratch - express, mongodb (mongoose).
Stars: ✭ 153 (+135.38%)
Mutual labels:  authentication, jwt, authorization
Cloudfront Auth
An AWS CloudFront [email protected] function to authenticate requests using Google Apps, Microsoft, Auth0, OKTA, and GitHub login
Stars: ✭ 471 (+624.62%)
Mutual labels:  authentication, jwt, authorization
Spark Pac4j
Security library for Sparkjava: OAuth, CAS, SAML, OpenID Connect, LDAP, JWT...
Stars: ✭ 154 (+136.92%)
Mutual labels:  authentication, jwt, authorization
Sureness
A simple and efficient open-source security framework that focus on protection of restful api.
Stars: ✭ 254 (+290.77%)
Mutual labels:  authentication, jwt, authorization
Express Jwt
An example API for creating/verifying json web tokens
Stars: ✭ 105 (+61.54%)
Mutual labels:  authentication, jwt, authorization
Buji Pac4j
pac4j security library for Shiro: OAuth, CAS, SAML, OpenID Connect, LDAP, JWT...
Stars: ✭ 444 (+583.08%)
Mutual labels:  authentication, jwt, authorization
Play Pac4j
Security library for Play framework 2 in Java and Scala: OAuth, CAS, SAML, OpenID Connect, LDAP, JWT...
Stars: ✭ 375 (+476.92%)
Mutual labels:  authentication, jwt, authorization
Access
Ponzu Addon to manage API access grants and tokens for authentication
Stars: ✭ 13 (-80%)
Mutual labels:  authentication, jwt, authorization
Auth0.js
Auth0 headless browser sdk
Stars: ✭ 755 (+1061.54%)
Mutual labels:  authentication, jwt, authorization
Mern Boilerplate
Fullstack boilerplate with React, Redux, Express, Mongoose, Passport Local, JWT, Facebook and Google OAuth out of the box.
Stars: ✭ 112 (+72.31%)
Mutual labels:  authentication, jwt, authorization
Security.identity
.NET DevPack Identity is a set of common implementations to help you implementing Identity, Jwt, claims validation and another facilities
Stars: ✭ 165 (+153.85%)
Mutual labels:  authentication, jwt, authorization
Spring Webmvc Pac4j
Security library for Spring Web MVC: OAuth, CAS, SAML, OpenID Connect, LDAP, JWT...
Stars: ✭ 110 (+69.23%)
Mutual labels:  authentication, jwt, authorization
Spring Security Pac4j
pac4j security library for Spring Security: OAuth, CAS, SAML, OpenID Connect, LDAP, JWT...
Stars: ✭ 231 (+255.38%)
Mutual labels:  authentication, jwt, authorization
Authex
Authex is an opinionated JWT authentication and authorization library for Elixir.
Stars: ✭ 73 (+12.31%)
Mutual labels:  authentication, jwt, authorization
Spring Security React Ant Design Polls App
Full Stack Polls App built using Spring Boot, Spring Security, JWT, React, and Ant Design
Stars: ✭ 1,336 (+1955.38%)
Mutual labels:  authentication, jwt, authorization
Securing Restful Apis With Jwt
How to secure a Nodejs RESTful CRUD API using JSON web tokens?
Stars: ✭ 301 (+363.08%)
Mutual labels:  authentication, jwt, authorization
Cerberus
A demonstration of a completely stateless and RESTful token-based authorization system using JSON Web Tokens (JWT) and Spring Security.
Stars: ✭ 482 (+641.54%)
Mutual labels:  authentication, jwt, authorization

grpc-auth-example

Examples of client authentication with gRPC. Both server-side and client-side implementations are shown. All authentication is performed in a server-side interceptor implemented in the auth package.

TLS Client Certificate Authentication

The first type of authentication uses TLS Certificate subjects to validate that the correct client is connecting. This, of course, relies on the issue certificate authority only issuing certificates with the correct subject to the correct service, but that is outside the scope of this repository.

On the client side, we create a certificate with the appropriate subject:

pk, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
    return nil, err
}

template := &x509.Certificate{
    SerialNumber: serialNumber,
    Subject: pkix.Name{
        Organization: []string{"Acme Co"},
        CommonName:   username, // Will be checked by the server
    },
    NotBefore:             time.Now(),
    NotAfter:              time.Now().Add(time.Hour),
    KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
    ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
    BasicConstraintsValid: true,
}

cert, err := x509.CreateCertificate(rand.Reader, template, insecure.Cert.Leaf, pk.Public(), insecure.Cert.PrivateKey)
if err != nil {
    return nil, err
}

tlsCert := tls.Certificate{
    Certificate: [][]byte{cert},
    PrivateKey:  pk,
}

We then use the certificate for transport security when dialing:

tlsConfig := &tls.Config{
    Certificates: []tls.Certificate{tlsCert},
    RootCAs:      insecure.CertPool,
}

conn, err := grpc.DialContext(ctx, net.JoinHostPort(addr, port),
    grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)),
)

On the server side, we use the grpc/peer package to find the subject of the client side certificate:

p, ok := peer.FromContext(ctx)
if !ok {
    return status.Error(codes.Unauthenticated, "no peer found")
}

tlsAuth, ok := p.AuthInfo.(credentials.TLSInfo)
if !ok {
    return status.Error(codes.Unauthenticated, "unexpected peer transport credentials")
}

if len(tlsAuth.State.VerifiedChains) == 0 || len(tlsAuth.State.VerifiedChains[0]) == 0 {
    return status.Error(codes.Unauthenticated, "could not verify peer certificate")
}

// Check subject common name against configured username
if tlsAuth.State.VerifiedChains[0][0].Subject.CommonName != a.Username {
    return status.Error(codes.Unauthenticated, "invalid subject common name")
}

return nil

This of course requires the server to verify incoming client certs, so remember to configure the appropriate tls.Config.ClientAuth value. In this example, we use tls.VerifyClientCertIfGiven to allow clients both with and without certificates.

Token based authentication

Secondly we've got token based authentication, which sends the authentication details in the request headers. On the client side this means implementing grpc/credentials.PerRPCCredentials:

type tokenAuth struct {
	token string
}

func (t tokenAuth) GetRequestMetadata(ctx context.Context, in ...string) (map[string]string, error) {
	return map[string]string{
		"authorization": "Bearer " + t.token,
	}, nil
}

func (tokenAuth) RequireTransportSecurity() bool {
	return true
}

We then use the tokenAuth struct when dialling:

conn, err := grpc.DialContext(ctx, net.JoinHostPort(addr, port),
    grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(insecure.CertPool, "")),
    grpc.WithPerRPCCredentials(tokenAuth{
        token: token,
    }),
)

On the server side, we simply check the header for the token value, but, of course, if you were using a real token you might want to parse it and perform some validation as well.

const prefix = "Bearer "
if !strings.HasPrefix(auth, prefix) {
	return ctx, status.Error(codes.Unauthenticated, `missing "Bearer " prefix in "Authorization" header`)
}

if strings.TrimPrefix(auth, prefix) != a.Token {
	return ctx, status.Error(codes.Unauthenticated, "invalid token")
}

HTTP Basic authentication

Much like the token based authentication, this uses PerRPCCredentials, with the only difference being the contents of the header:

type basicAuth struct {
	username string
	password string
}

func (b basicAuth) GetRequestMetadata(ctx context.Context, in ...string) (map[string]string, error) {
	auth := b.username + ":" + b.password
	enc := base64.StdEncoding.EncodeToString([]byte(auth))
	return map[string]string{
		"authorization": "Basic " + enc,
	}, nil
}

func (basicAuth) RequireTransportSecurity() bool {
	return true
}

And dialling:

conn, err := grpc.DialContext(ctx, net.JoinHostPort(addr, port),
	grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(insecure.CertPool, "")),
	grpc.WithPerRPCCredentials(basicAuth{
		username: username,
		password: password,
	}),
)

The server has to parse the the header:

const prefix = "Basic "
if !strings.HasPrefix(auth, prefix) {
    return ctx, status.Error(codes.Unauthenticated, `missing "Basic " prefix in "Authorization" header`)
}

c, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
if err != nil {
    return ctx, status.Error(codes.Unauthenticated, `invalid base64 in header`)
}

cs := string(c)
s := strings.IndexByte(cs, ':')
if s < 0 {
    return ctx, status.Error(codes.Unauthenticated, `invalid basic auth format`)
}

user, password := cs[:s], cs[s+1:]
if user != a.Username || password != a.Password {
    return ctx, status.Error(codes.Unauthenticated, "invalid user or password")
}
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].