go-pkgz / go-pkgz/auth

Support OpenID and 3rd party IdTokens with cookie-less authentication

Open
#101 7 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Go
Stars
1.4k
Forks
97
Avg merge
2d 21h
Merged PRs (30d)
2

Description

There are probably quite a few parts in this issue, I totally see those as separate small PRs / issues.

Context

Currently, auth package supports various OAuth2 providers and acts as a OAuth2 Authorization Server / proxy (without strongly committing to RFC) by issuing self-signed ID tokens based on info provided by /userinfo response, which are passed via a cookie, with extra XSRF protection.

Proposal

Support OpenID providers and ID tokens issued by an external identity provider as authentication tokens. In this scenario, the server won't have private keys and won't issue ID tokens itself. Potentially support OpenID Connect Discovery protocol. Unlike general OAuth2 spec, OpenID supports issuing signed ID tokens bound to a particular user, so these tokens can be used for authentication.

How I see the potential configuration:

    // code below will fetch OpenID Connect Discovery config 
    // from https://accounts.google.com/.well-known/openid-configuration
    // then it'll load keys from "jwks_uri" endpoint and store them under "google" provider
    service.AddOpenIDProvider("google", "https://accounts.google.com", "client-id", "client-secret") 
    
    m := service.Middleware()
    router := chi.NewRouter()

    // setup auth routes
    authRoutes, avaRoutes := service.Handlers()

    // for OpenID providers, /auth handler won't just fetch access token + userinfo, 
    // but will actually request a signed ID token from the provider. 
    // This token can be then passed to the client as is, as it is signed already 
    // and we have public keys for validate it.
    router.Mount("/auth", authRoutes)  // add auth handlers
    router.Mount("/avatar", avaRoutes) // add avatar handler


    // m.OpenIDAuth won't use own keys defined in opts.SecretReader, but instead will use public keys loaded before
    // the provider can be identified either by "iss" claim or manually configured, i.e. m.OpenIDAuth("google")

    // Also, OpenIDAuth shouldn't require a cookie, but Authorization: Bearer <jwt> header to work.
    router.With(m.OpenIDAuth).Get("/api-endpoint", protectedRouteHandler) // protected api

    router.With(m.OpenIDAuth(func(claims token.Claims) bool {
        // do any authorization checks on the token claims, e.g. Role 
    })).Get("/api-endpoint", protectedRouteHandler) // protected api

With OpenIDAuth authentication middleware, the server should act as a OAuth2 Resource Server, i.e. to expect Authorization: Bearer <jwt> header and use that for authentication.

Having this would allow:

  • Remove need in issuing auth (ID) tokens, as well as managing signing keys
  • Easy integration with new providers
  • Unify user / API authentication middleware (by using Authorization header)
  • Multiple services using the same auth middleware configuration without sharing secrets

Considerations:

  • Some parts of configuration options are irrelevant for OpenID providers, where auth is only acting as a authentication proxy basically. Like opts.ClaimsUpdater won't work - since we don't have private keys, we can't modify claims. Probably OpenID should have own configuration options?
  • How to pass a signed ID token to the client? I think the cookie approach can still be used, but instead of checking the cookie, Authorization header should be checked, which is set from the cookie. This kind of gives XSRF protection for free.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the auth package's existing OAuth2 handlers, middleware, provider configuration, and token validation flow. Break the proposal into separate changes for OpenID discovery and keys, bearer-token authentication, and provider-issued ID tokens; done means each chosen part has focused tests covering configuration, validation, and the Authorization header path.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
api, authentication, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.