⛩️ Go library for protecting HTTP handlers with authorization bearer token.

g8

build Go Report Card codecov Go version Go Reference

G8, pronounced Gate, is a simple Go library for protecting HTTP handlers with tokens.

Tired of constantly re-implementing a security layer for each of applications? Me too, that's why I made G8.

Installation

go get -u github.com/TwinProduction/g8

Usage

Because the entire purpose of G8 is to NOT waste time configuring the layer of security, the primary emphasis is to keep it as simple as possible.

Simple

Just want a simple layer of security without the need for advanced permissions? This configuration is what you're looking for.

gate := g8.NewGate(g8.NewAuthorizationService().WithToken("mytoken"))
router := http.NewServeMux()
router.Handle("/unprotected", yourHandler)
router.Handle("/protected", gate.Protect(yourHandler))
http.ListenAndServe(":8080", router)

The endpoint /protected is now only accessible if you pass the header Authorization: Bearer mytoken.

If you use http.HandleFunc instead of http.Handle, you may use gate.ProtectFunc(yourHandler) instead.

Advanced permissions

If you have tokens with more permissions than others, g8's permission system will make managing authorization a breeze.

Rather than registering tokens, think of it as registering clients, the only difference being that clients may be configured with permissions while tokens cannot.

gate := g8.NewGate(g8.NewAuthorizationService().WithClient(g8.NewClient("mytoken").WithPermission("admin")))
router := http.NewServeMux()
router.Handle("/unprotected", yourHandler)
router.Handle("/protected-with-admin", gate.ProtectWithPermissions(yourHandler, []string{"admin"}))
http.ListenAndServe(":8080", router)

The endpoint /protected-with-admin is now only accessible if you pass the header Authorization: Bearer mytoken, because the client with the token mytoken has the permission admin. Note that the following handler would also be accessible with that token:

router.Handle("/protected", gate.Protect(yourHandler))

To clarify, both clients and tokens have access to handlers that aren't protected with extra permissions, and essentially, tokens are registered as clients with no extra permissions in the background.

Creating a token like so:

gate := g8.NewGate(g8.NewAuthorizationService().WithToken("mytoken"))

is the equivalent of creating the following client:

gate := g8.NewGate(g8.NewAuthorizationService().WithClient(g8.NewClient("mytoken")))

With client provider

A client provider's task is to retrieve a Client from an external source (e.g. a database) when provided with a token. You should use a client provider when you have a lot of tokens and it wouldn't make sense to register all of them using AuthorizationService's WithToken/WithTokens/WithClient/WithClients.

Note that the provider is used as a fallback source. As such, if a token is explicitly registered using one of the 4 aforementioned functions, the client provider will not be used.

clientProvider := g8.NewClientProvider(func(token string) *g8.Client {
    // We'll assume that the following function calls your database and returns a struct "User" that 
    // has the user's token as well as the permissions granted to said user
    user := database.GetUserByToken(token)
    if user != nil {
        return g8.NewClient(user.Token).WithPermissions(user.Permissions)
    }
    return nil
})
gate := g8.NewGate(g8.NewAuthorizationService().WithClientProvider(clientProvider))

You can also configure the client provider to cache the output of the function you provide to retrieve clients by token:

clientProvider := g8.NewClientProvider(...).WithCache(ttl, maxSize)

Since g8 leverages TwinProduction/gocache, you can also use gocache's constants for configuring the TTL and the maximum size:

  • Setting the TTL to gocache.NoExpiration (-1) will disable the TTL.
  • Setting the maximum size to gocache.NoMaxSize (0) will disable the maximum cache size

If you're using a TTL and have a lot of tokens (100k+), you may want to use clientProvider.StartJanitor() to allow the cache to passively delete expired entries. If you have to re-initialize the client provider after the janitor has been started, make sure to stop the janitor first (clientProvider.StopJanitor()). This is because the janitor runs on a separate goroutine, thus, if you were to re-create a client provider and re-assign it, the old client provider would still exist in memory with the old cache. I'm only specifying this for completeness, because for the overwhelming majority of people, the gate will be created on application start and never modified again until the application shuts down, in which case, you don't even need to worry about stopping the janitor.

To avoid any misunderstandings, using a client provider is not mandatory. If you only have a few tokens and you can load them on application start, you can just leverage AuthorizationService's WithToken/WithTokens/WithClient/WithClients.

AuthorizationService

As the previous examples may have hinted, there are several ways to create clients. The one thing they have in common is that they all go through AuthorizationService, which is in charge of both managing clients and determining whether a request should be blocked or allowed through.

Function Description
WithToken Creates a single static client with no extra permissions
WithTokens Creates a slice of static clients with no extra permissions
WithClient Creates a single static client
WithClients Creates a slice of static clients
WithClientProvider Creates a client provider which will allow a fallback to a dynamic source (e.g. to a database) when a static client is not found

Except for WithClientProvider, every functions listed above can be called more than once. As a result, you may safely perform actions like this:

authorizationService := g8.NewAuthorizationService().
    WithToken("123").
    WithToken("456").
    WithClient(g8.NewClient("789").WithPermission("admin"))
gate := g8.NewGate(authorizationService)

Be aware that g8.Client supports a list of permissions as well. You may call WithPermission several times, or call WithPermissions with a slice of permissions instead.

Permissions

Unlike client permissions, handler permissions are requirements.

A client may have as many permissions as you want, but for said client to have access to a handler protected by permissions, the client must have all permissions defined by said handler in order to have access to it.

In other words, a client with the permissions create, read, update and delete would have access to all of these handlers:

gate := g8.NewGate(g8.NewAuthorizationService().WithClient(g8.NewClient("mytoken").WithPermissions([]string{"create", "read", "update", "delete"})))
router := http.NewServeMux()
router.Handle("/", gate.Protect(homeHandler)) // equivalent of gate.ProtectWithPermissions(homeHandler, []string{})
router.Handle("/create", gate.ProtectWithPermissions(createHandler, []string{"create"}))
router.Handle("/read", gate.ProtectWithPermissions(readHandler, []string{"read"}))
router.Handle("/update", gate.ProtectWithPermissions(updateHandler, []string{"update"}))
router.Handle("/delete", gate.ProtectWithPermissions(deleteHandler, []string{"delete"}))
router.Handle("/crud", gate.ProtectWithPermissions(crudHandler, []string{"create", "read", "update", "delete"}))

But it would not have access to the following handler, because while mytoken has the read permission, it does not have the backup permission:

router.Handle("/backup", gate.ProtectWithPermissions(&testHandler{}, []string{"read", "backup"}))
Owner
Chris C.
I love programming
Chris C.
Comments
  • Implement caching in the ClientProvider

    Implement caching in the ClientProvider

    Changelog

    Fixes #1

    • New fields in ClientProvider
    • Added a WithCache function to decorate over ClientProvider
    • Modified GetClientByToken function accordingly to use cache

    Some comments: We store the ttl property in the struct because we would need it in the WithCache function. The reason I didn't add a maxSize property to the struct is because we won't use it. I kept the cache property because, it is a direct indicator of whether or not there is a need to call gocache.Get(). I don't know if gocache is good property name.

  • Bump codecov/codecov-action from 2.1.0 to 3.1.1

    Bump codecov/codecov-action from 2.1.0 to 3.1.1

    Bumps codecov/codecov-action from 2.1.0 to 3.1.1.

    Release notes

    Sourced from codecov/codecov-action's releases.

    3.1.1

    What's Changed

    New Contributors

    Full Changelog: https://github.com/codecov/codecov-action/compare/v3.1.0...v3.1.1

    v3.1.0

    3.1.0

    Features

    ... (truncated)

    Changelog

    Sourced from codecov/codecov-action's changelog.

    3.1.1

    Fixes

    • #661 Update deprecation warning
    • #593 Create codeql-analysis.yml
    • #712 README: fix typo
    • #725 fix: Remove a blank row
    • #726 Update README.md with correct badge version
    • #633 Create scorecards-analysis.yml
    • #747 fix: add more verbosity to validation
    • #750 Regenerate scorecards-analysis.yml
    • #774 Switch to v3
    • #783 Fix network entry in table
    • #791 Trim arguments after splitting them
    • #769 Plumb failCi into verification function.

    Dependencies

    • #713 build(deps-dev): bump typescript from 4.6.3 to 4.6.4
    • #714 build(deps): bump node-fetch from 3.2.3 to 3.2.4
    • #724 build(deps): bump github/codeql-action from 1 to 2
    • #717 build(deps-dev): bump @​types/jest from 27.4.1 to 27.5.0
    • #729 build(deps-dev): bump @​types/node from 17.0.25 to 17.0.33
    • #734 build(deps-dev): downgrade @​types/node to 16.11.35
    • #723 build(deps): bump actions/checkout from 2 to 3
    • #733 build(deps): bump @​actions/github from 5.0.1 to 5.0.3
    • #732 build(deps): bump @​actions/core from 1.6.0 to 1.8.2
    • #737 build(deps-dev): bump @​types/node from 16.11.35 to 16.11.36
    • #749 build(deps): bump ossf/scorecard-action from 1.0.1 to 1.1.0
    • #755 build(deps-dev): bump typescript from 4.6.4 to 4.7.3
    • #759 build(deps-dev): bump @​types/node from 16.11.36 to 16.11.39
    • #762 build(deps-dev): bump @​types/node from 16.11.39 to 16.11.40
    • #746 build(deps-dev): bump @​vercel/ncc from 0.33.4 to 0.34.0
    • #757 build(deps): bump ossf/scorecard-action from 1.1.0 to 1.1.1
    • #760 build(deps): bump openpgp from 5.2.1 to 5.3.0
    • #748 build(deps): bump actions/upload-artifact from 2.3.1 to 3.1.0
    • #766 build(deps-dev): bump typescript from 4.7.3 to 4.7.4
    • #799 build(deps): bump openpgp from 5.3.0 to 5.4.0
    • #798 build(deps): bump @​actions/core from 1.8.2 to 1.9.1

    3.1.0

    Features

    • #699 Incorporate xcode arguments for the Codecov uploader

    Dependencies

    • #694 build(deps-dev): bump @​vercel/ncc from 0.33.3 to 0.33.4
    • #696 build(deps-dev): bump @​types/node from 17.0.23 to 17.0.25
    • #698 build(deps-dev): bump jest-junit from 13.0.0 to 13.2.0

    3.0.0

    Breaking Changes

    • #689 Bump to node16 and small fixes

    ... (truncated)

    Commits
    • d9f34f8 release: update changelog and version to 3.1.1 (#828)
    • 0e9e7b4 Plumb failCi into verification function. (#769)
    • 7f20bd4 build(deps): bump @​actions/core from 1.8.2 to 1.9.1 (#798)
    • 13bc253 build(deps): bump openpgp from 5.3.0 to 5.4.0 (#799)
    • 5c0da1b Trim arguments after splitting them (#791)
    • 68d5f6d Fix network entry in table (#783)
    • 2a829b9 Switch to v3 (#774)
    • 8e09eaf build(deps-dev): bump typescript from 4.7.3 to 4.7.4 (#766)
    • 39e2229 build(deps): bump actions/upload-artifact from 2.3.1 to 3.1.0 (#748)
    • b2b7703 build(deps): bump openpgp from 5.2.1 to 5.3.0 (#760)
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
  • Support using cookie as a form of identification

    Support using cookie as a form of identification

    Rather than only supporting the Authorization header as a way to identify a user, it would be nice if we could use the client provider to retrieve the user through a session cookie.

  • Implement caching in the ClientProvider

    Implement caching in the ClientProvider

    Implementing a cache with a configurable TTL as well as a configurable maximum size in ClientProvider could be very useful to help preventing unnecessary load on whatever service or infrastructure component ClientProvider's getClientByTokenFunc function is calling.

    The implementation:

    • Must be able to have a maximum cache size (e.g. 10000)
    • Must be able to have a configurable TTL (e.g. 1 hour)
    • Must be able to cache invalid tokens with a shorter entry TTL (e.g. 30 minutes)

    Being the self-promoting person that I am, I think TwinProduction/gocache would fit this role perfectly.

  • Bump github.com/TwiN/gocache/v2 from 2.1.2 to 2.2.0

    Bump github.com/TwiN/gocache/v2 from 2.1.2 to 2.2.0

    Bumps github.com/TwiN/gocache/v2 from 2.1.2 to 2.2.0.

    Release notes

    Sourced from github.com/TwiN/gocache/v2's releases.

    v2.2.0

    What's Changed

    • feat: Add support for a default TTL by @​TwiN in TwiN/gocache#8
    • fix: Make EvictionPolicy options const instead of var

    Full Changelog: https://github.com/TwiN/gocache/compare/v2.1.2...v2.2.0

    Commits
    • 1651d3a docs: Fix mistake in SetAllWithTTL description
    • 2933a71 feat: Add support for a default TTL
    • b4077b2 fix: Make EvictionPolicy options consts instead of vars
    • See full diff in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
  • Bump github.com/TwiN/gocache/v2 from 2.1.1 to 2.1.2

    Bump github.com/TwiN/gocache/v2 from 2.1.1 to 2.1.2

    Bumps github.com/TwiN/gocache/v2 from 2.1.1 to 2.1.2.

    Release notes

    Sourced from github.com/TwiN/gocache/v2's releases.

    v2.1.2

    What's Changed

    Full Changelog: https://github.com/TwiN/gocache/compare/v2.1.1...v2.1.2

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
  • Add support for rate limiting

    Add support for rate limiting

    It would be nice to have a configuration for rate limiting on Gate.

    Something like this:

    gate := g8.NewGate(nil).WithRateLimit(100)
    

    where 100 is the maximum number of requests per second.

  • feat: ClientProvider.cache as an interface to support external cache (e.g. redis)

    feat: ClientProvider.cache as an interface to support external cache (e.g. redis)

    Describe the feature request

    At present it looks like the client provider cache field is tightly coupled to the gocache. If a user wants to also use an external/shared/distributed cache then this isn't possible. It would be nice to allow more flexibility to the user in which caching solution they wish to use.

    Why do you personally want this feature to be implemented?

    to allow flexibility in choice of cache solution.

    How long have you been using this project?

    No response

    Additional information

    No response

Authorization and authentication. Learning go by writing a simple authentication and authorization service.

Authorization and authentication. Learning go by writing a simple authentication and authorization service.

Aug 5, 2022
Backend Development Rest Api Project for book management system. Used Features like redis, jwt token,validation and authorization.

Golang-restapi-project Simple Rest Api Project with Authentication, Autherization,Validation and Connection with redis File Structure ├── cache │ ├──

May 25, 2022
Go login handlers for authentication providers (OAuth1, OAuth2)
Go login handlers for authentication providers (OAuth1, OAuth2)

gologin Package gologin provides chainable login http.Handler's for Google, Github, Twitter, Facebook, Bitbucket, Tumblr, or any OAuth1 or OAuth2 auth

Dec 30, 2022
This package provides json web token (jwt) middleware for goLang http servers

jwt-auth jwt auth middleware in goLang. If you're interested in using sessions, checkout my sessions library! README Contents: Quickstart Performance

Dec 5, 2022
An authorization library that supports access control models like ACL, RBAC, ABAC in Golang
An authorization library that supports access control models like ACL, RBAC, ABAC in Golang

Casbin News: still worry about how to write the correct Casbin policy? Casbin online editor is coming to help! Try it at: https://casbin.org/editor/ C

Jan 2, 2023
An authorization library that supports access control models like ACL, RBAC, ABAC in Golang
An authorization library that supports access control models like ACL, RBAC, ABAC in Golang

Casbin News: still worry about how to write the correct Casbin policy? Casbin online editor is coming to help! Try it at: https://casbin.org/editor/ C

Jan 4, 2023
Go library providing in-memory implementation of an OAuth2 Authorization Server / OpenID Provider

dispans Go library providing in-memory implementation of an OAuth2 Authorization Server / OpenID Provider. The name comes from the Swedish word dispen

Dec 22, 2021
A library for Go client applications that need to perform OAuth authorization against a server
A library for Go client applications that need to perform OAuth authorization against a server

oauth-0.8.0.zip oauth A library for Go client applications that need to perform OAuth authorization against a server, typically GitHub.com. Traditiona

Oct 13, 2021
JSON Web Token library

About … a JSON Web Token (JWT) library for the Go programming language. Feature complete Full test coverage Dependency free Key management The API enf

Dec 19, 2022
ACL, RBAC, ABAC authorization middleware for KubeSphere

casbin-kubesphere-auth Casbin-kubesphere-auth is a plugin which apply several security authentication check on kubesphere via casbin. This plugin supp

Jun 9, 2022
an stateless OpenID Connect authorization server that mints ID Tokens from Webauthn challenges

Webauthn-oidc Webauthn-oidc is a very minimal OIDC authorization server that only supports webauthn for authentication. This can be used to bootstrap

Nov 6, 2022
policy - the CLI for managing authorization policies
 policy - the CLI for managing authorization policies

policy - the CLI for managing authorization policies The policy CLI is a tool for building, versioning and publishing your authorization policies. It

Dec 30, 2022
telegram authorization in telegram without using a widget

TGAH - telegram Authorization Example of authorization in telegram without using a widget Installation go get -d github.com/tioffs/tgah@master Setti

Jun 6, 2022
Authorization As A Service

a3s NOTE: this is a work in progress and this software is not usable yet a3s (stands for Auth As A Service) is an authentication and ABAC authorizatio

Dec 14, 2022
A demo of authentication and authorization using jwt
A demo of authentication and authorization using jwt

Nogopy Hi, this a demo of how to use jwt for authentication in microservices Keep in mind that this is a demo of how to authenticate using jwt, we don

Nov 1, 2021
Mini-framework for multiple authentication and authorization schemes
Mini-framework for multiple authentication and authorization schemes

Go authorization pattern This repository demonstrates an authorization pattern that allows multiple schemes. Demo To start the demo run the following

Dec 30, 2021
Example of a simple application which is powered by a third-party oAuth 2.0 server for it's authentication / authorization. Written in Golang.

go mod init github.com/bartmika/osin-thirdparty-example go get github.com/spf13/cobra go get github.com/openshift/osin go get github.com/openshift/osi

Jan 4, 2022
Authelia: an open-source authentication and authorization server providing two-factor authentication
Authelia: an open-source authentication and authorization server providing two-factor authentication

Authelia is an open-source authentication and authorization server providing two

Jan 5, 2022
🔑 Authz0 is an automated authorization test tool. Unauthorized access can be identified based on URL and Role.
🔑 Authz0 is an automated authorization test tool. Unauthorized access can be identified based on URL and Role.

Authz0 is an automated authorization test tool. Unauthorized access can be identified based on URL and Role. URLs and Roles are managed as YAML-based

Dec 20, 2022