We're so excited you're interested in helping with Authorizer! We are happy to help you get started, even if you don't have any previous open-source experience 😊
- Take a look at How to Contribute to an Open Source Project on GitHub
- Go through the Authorizer Code of Conduct
- Check our Github Issues to see if someone has already answered your question.
- Join our community on Discord and feel free to ask us your questions
As you gain experience with Authorizer, please help answer other people's questions! 🙏
You can get started by taking a look at our Github issues
If you find one that looks interesting and no one else is already working on it, comment on that issue and start contributing 🙂.
Please ask as many questions as you need, either directly in the issue or on Discord. We're happy to help!:raised_hands:
- More tests
- Improved Docs
- Improved error messages
- Educational content like blogs, videos, courses
- OS: Linux or macOS or Windows
- Go >= 1.24 (see
go.mod) - Node.js >= 18 and npm (only if building web app or dashboard)
- Architecture of Authorizer
- GraphQL APIs
- Migration Guide (v1 → v2) – v2 uses CLI-based configuration
- Fork the authorizer repository (Skip this step if you have access to repo)
- Clone repo:
git clone https://github.com/authorizerdev/authorizer.gitor use the forked url from step 1 - Change directory:
cd authorizer - Build the server:
make build(orgo build -o build/authorizer .) - (Optional) Build the web app and dashboard:
make build-appandmake build-dashboard - Run locally:
make dev(uses SQLite and demo secrets for development)
v2: The server does not read from
.env. All configuration is passed via CLI arguments. See MIGRATION.md.
- Modify
internal/graph/schema.graphqls(or other files ininternal/graph/) - Run
make generate-graphqlto regenerate models and resolvers - If a new mutation or query is added, implement the resolver in
internal/graph/(resolver layout follows schema)
-
Run
make generate-db-template dbname=NEW_DB_NAME- e.g.
make generate-db-template dbname=dynamodb
This copies
internal/storage/db/provider_template/tointernal/storage/db/NEW_DB_NAME/and renames the package. The template already stubs every method ofstorage.Provider(internal/storage/provider.go) across all feature areas — users, sessions, webhooks, email templates, OTP, authenticators, memory-store (session/MFA/OAuth-state), audit logs, clients, trusted issuers, SAML (SP + IDP keys), SCIM (endpoints + groups), WebAuthn credentials, organizations, org memberships, org domains, and federated identities. Rungo test ./internal/storage/db/NEW_DB_NAME/...any time to confirm it still satisfiesstorage.Providerin full —interface_test.gofails to compile the instant a method goes missing. - e.g.
-
Change the
providerstruct andNewProviderinNEW_DB_NAME/provider.goto hold and construct your actual database client (the template ships with a placeholder*gorm.DBfield — replace it). -
Implement each stubbed method for real, one feature file at a time. Use an existing provider as a reference for the query patterns of a similar backend:
- SQL-like/GORM backend →
internal/storage/db/sql/ - Document store →
internal/storage/db/mongodb/orinternal/storage/db/arangodb/ - Wide-column store →
internal/storage/db/cassandradb/ - Key-value store →
internal/storage/db/dynamodb/orinternal/storage/db/couchbase/
- SQL-like/GORM backend →
-
Wire the new provider into
storage.New()(internal/storage/provider.go) behind its config-selected database type. -
Add the new provider to the storage test matrix (
TEST_DBS) and amake test-NEW_DB_NAME/test-cleanup-NEW_DB_NAMEDocker target in theMakefile, following the pattern of the existingtest-postgres/test-mongodbtargets.
Note:
go test ./internal/storage/db/NEW_DB_NAME/...will fail to compile with adoes not implement storage.Provider (missing method ...)error until every method is implemented. This check lives in a_testfile rather than inprovider.goitself —internal/storageimports every concrete provider (including yours, once step 4 is done), so a same-package assertion would create an import cycle.
Make sure you test before creating a PR.
The main make test target spins up Postgres, Redis, ScyllaDB, MongoDB, ArangoDB, DynamoDB, and Couchbase via Docker, runs the Go test suite, then tears down containers.
For local development without full DB matrix:
make dev # run server for manual testing
go test -v ./... # run tests (requires Docker for full suite)If you are adding a new resolver:
- Create a new test file in
internal/integration_tests/(naming:resolver_name_test.go) - Follow the existing pattern using
getTestConfig()andinitTestSetup()
Command to run full test suite:
make testManual Testing:
For manually testing using graphql playground, you can paste following queries and mutations in your playground and test it
mutation Signup {
signup(
params: {
email: "lakhan@yopmail.com"
password: "test"
confirm_password: "test"
given_name: "lakhan"
}
) {
message
user {
id
family_name
given_name
email
email_verified
}
}
}
mutation ResendEamil {
resend_verify_email(
params: { email: "lakhan@yopmail.com", identifier: "basic_auth_signup" }
) {
message
}
}
query GetVerifyRequests {
_verification_requests {
id
token
expires
identifier
}
}
mutation VerifyEmail {
verify_email(params: { token: "" }) {
access_token
expires_at
user {
id
email
given_name
email_verified
}
}
}
mutation Login {
login(params: { email: "lakhan@yopmail.com", password: "test" }) {
access_token
expires_at
user {
id
family_name
given_name
email
}
}
}
query GetSession {
session {
access_token
expires_at
user {
id
given_name
family_name
email
email_verified
signup_methods
created_at
updated_at
}
}
}
mutation ForgotPassword {
forgot_password(params: { email: "lakhan@yopmail.com" }) {
message
}
}
mutation ResetPassword {
reset_password(
params: { token: "", password: "test", confirm_password: "test" }
) {
message
}
}
mutation UpdateProfile {
update_profile(params: { family_name: "samani" }) {
message
}
}
query GetUsers {
_users {
id
email
email_verified
given_name
family_name
picture
signup_methods
phone_number
}
}
mutation MagicLinkLogin {
magic_link_login(params: { email: "test@yopmail.com" }) {
message
}
}
mutation Logout {
logout {
message
}
}
mutation UpdateUser {
_update_user(
params: {
id: "dafc9400-d603-4ade-997c-83fcd54bbd67"
roles: ["user", "admin"]
}
) {
email
roles
}
}
mutation DeleteUser {
_delete_user(params: { email: "signup.test134523@yopmail.com" }) {
message
}
}