Skip to main content

Authentication

The Authentication Library is a powerful and flexible solution for implementing user authentication and access control in your applications. It provides a secure and reliable way to manage user authentication, verify user identities, and enforce authorization rules.

Workflow

auth_workflow

Features

  • JWT Signer Configuration: The library allows you to create a signer with JWT configuration input, enabling you to customize the JWT signing algorithm, secret keys, expiration time, and other settings according to your security requirements.

  • HTTP API for Platform Sign-In: The library exposes an HTTP API specifically designed for platform sign-in. It supports OAuth-based authentication flows and integrates with popular identity providers such as Google, Facebook, or GitHub. This allows users to sign in using their existing platform accounts seamlessly.

  • gRPC APIs for Access Token Exchange:: It provides a set of gRPC APIs for clients to exchange access tokens securely. These APIs handle the token validation, decoding, and verification processes, ensuring the integrity and authenticity of the tokens.

  • Token Validation and Verification: When clients exchange access tokens, the library performs thorough validation and verification checks to ensure the tokens are valid, have not expired, and are issued by a trusted authority. This prevents unauthorized access to your application's resources.

  • Customizable Token Payload: The library will be provided flexibility in defining the payload of the JWT tokens in the future. You can include custom claims, user roles, permissions, or any other relevant information in the token payload, allowing for granular access control within your application.

  • Secure Token Storage: To enhance security, the library assists in securely storing and managing JWT tokens. It supports encryption, secure transmission over HTTPS, and provides best practices for token storage on the server-side.

  • Extensibility and Customization: The JWT Authentication Library is designed to be highly extensible and customizable. It provides hooks and extension points to integrate with your existing user databases, authentication systems, or implement custom token handling logic.

Getting Started

To begin using the Library, follow the installation examples. Once installed, refer to the documentation for comprehensive guides on configuring the JWT signer, utilizing the gRPC APIs for token exchange, and setting up the HTTP API for platform sign-in.

Contributing

We appreciate community contributions to enhance the JWT Authentication Library. If you encounter any bugs, have feature requests, or would like to contribute code improvements, please refer to the contribution guidelines outlined in the repository.

Protocol Message

  • We only accept custom message, it be defined in auth.proto.

Method

  • GetRegisterHandler: the method is used for set to HTTP handler to handle register/signIn requests from platforms.

  • RegisterAuthServer: the method is used for to serve the Auth server with your gRPC application server. In this server, we need to implement an authorization server that is responsible for validating user tokens and checking their validity. To facilitate this functionality, we will set up a gateway that serves as an entry point for API calls. The gateway will handle incoming requests from clients and route them to the appropriate endpoints in the authorization server. This setup allows us to centralize the token validation logic and ensure that only valid user tokens are accepted.

  • Functions: We have implemented two functions (Register, ExchangeToken) to handle the APIs mentioned above. These functions are designed to support developers in implementing the APIs directly within their applications, eliminating the need to import an external client. By using these functions, developers can seamlessly integrate the desired functionality into their applications without relying on an external library or module. This approach allows for greater flexibility and control over the implementation of the APIs within the application codebase.

Examples

package main

import (
"context"
"fmt"
"log"
"net"
"sync"

"net/http"

_ "github.com/mattn/go-sqlite3"
carbon "gitlab.ugaming.io/marketplace/carbon/api"
"gitlab.ugaming.io/marketplace/logger/pkg/logging"
mykit "gitlab.ugaming.io/marketplace/mykit/pkg/api"
redis "gitlab.ugaming.io/marketplace/redis/api"
rediscli "gitlab.ugaming.io/marketplace/redis/pkg/client"
"go.uber.org/zap"
"google.golang.org/grpc"

authcli "gitlab.ugaming.io/marketplace/edk/pkg/client/auth"
"gitlab.ugaming.io/marketplace/edk/pkg/client/auth/token"
companycli "gitlab.ugaming.io/marketplace/edk/pkg/client/company"
usercli "gitlab.ugaming.io/marketplace/edk/pkg/client/user"
"gitlab.ugaming.io/marketplace/edk/pkg/ent"
)

func main() {
client, err := ent.Open("sqlite3", "file:ent?mode=memory&_fk=1")
if err != nil {
log.Fatal("OpenEntClient", err)
}
defer client.Close()

err = client.Schema.Create(context.Background())
if err != nil {
log.Fatal("OpenEntClient", err)
}

iframeUrl := "https://examples/auth"

// The company info (in json string format an) is set in config
companyStr := "{\"companies\":[{\"full_name\":\"IGaming\",\"short_name\":\"iga\",\"id\":\"9b3021b5-e2d7-4123-a2e8-b530a5e90693\",\"key\":\"4be0fbef76ca43ba49aa25d4fc250ad0d35dd3f78a453468ecf86c7b41f11b2e\",\"url\":\"https://redline.stg.ugaming.tech/eagles\"},{\"full_name\":\"ServerAPITesting\",\"short_name\":\"server-test\",\"id\":\"31ab6bc5-5035-42e5-a6d7-982003b145c1\",\"key\":\"5b5dadb67ce3fa5bd49110948700408bd07fd8d6ae4ede94c447ff305e6286ff\",\"url\":\"https://poker.stg.ugaming.tech\"},{\"full_name\":\"Gameloot\",\"short_name\":\"gameloot\",\"id\":\"202d05e6-22f1-49af-85e9-c01ddaf6b99e\",\"key\":\"ec642cb37d6a9b871b567a55d0f12b633fa1bdb3e455d146c0679d2ab162f59a\",\"url\":\"https://benpha.henxui.fun/eagles\"}]}"

user := usercli.NewUserCache(client, usercli.WithRecordMode(50))
company, err := companycli.New(companyStr)
if err != nil {
log.Fatal("NewCompany", err)
}

redis, err := rediscli.New(&redis.Redis{
Address: "localhost:6379",
Namespace: "test-auth",
})
if err != nil {
log.Fatal("NewRedis", err)
}

signInToken, err := token.NewToken(
&carbon.JwtSigning{
ExpiresTime: 120,
PrivateKey: "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEILjElFx3rBSeN2u807DwLPUSGhKzg8LaMqy4I+sjDETV\n-----END PRIVATE KEY-----",
Issuer: "test-issuer",
DefaultAudience: "test-issuer",
},
redis,
)
if err != nil {
log.Fatal("NewSignInToken", err)
}

accessToken, err := token.NewToken(
&carbon.JwtSigning{
ExpiresTime: 86000,
PrivateKey: "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIFnp8RFEP1mHYSFR8FasOXtgDCzr4Gx1/aUWbSepTG0g\n-----END PRIVATE KEY-----",
Issuer: "test-issuer",
DefaultAudience: "test-issuer",
},
redis,
token.AllowMultiTokenActive(true), //optional, use when user can processing with multiple tokens
token.PrefixRedisKey("sign-in-token"), //optional
)
if err != nil {
log.Fatal("NewAccessToken", err)
}

auth := authcli.New(client, signInToken, accessToken, company, user, iframeUrl)

// HTTP
httpAddr := fmt.Sprintf(
"%s:%d",
"localhost",
8081,
)

http.HandleFunc("/api/auth/register", auth.GetRegisterHandler())

// gRPC
listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", "localhost", 8082))
if err != nil {
log.Fatal("failed to new listener", zap.Error(err))
}

service := mykit.NewService(
mykit.Listener(listener),
mykit.Server(grpc.NewServer()),
mykit.Logger(logging.Logger(context.Background())),
)
auth.RegisterAuthServer(service)

fmt.Println("starting server")
var wg sync.WaitGroup

wg.Add(1)
go func() {
defer wg.Done()
http.ListenAndServe(httpAddr, nil)
}()

wg.Add(1)
go func() {
defer wg.Done()
service.Serve()
}()

wg.Wait()
}