{"id":21432482,"url":"https://github.com/jamesrandall/stravatokenmanager","last_synced_at":"2026-03-04T19:32:35.776Z","repository":{"id":137262710,"uuid":"165046258","full_name":"JamesRandall/StravaTokenManager","owner":"JamesRandall","description":"C# project for managing the Strava token exchange process","archived":false,"fork":false,"pushed_at":"2019-11-05T13:10:12.000Z","size":41,"stargazers_count":2,"open_issues_count":1,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-21T13:43:34.503Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JamesRandall.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-01-10T11:15:21.000Z","updated_at":"2023-08-29T10:32:17.000Z","dependencies_parsed_at":null,"dependency_job_id":"1411eab1-3c59-4141-a0c5-6b2df20cf156","html_url":"https://github.com/JamesRandall/StravaTokenManager","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JamesRandall%2FStravaTokenManager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JamesRandall%2FStravaTokenManager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JamesRandall%2FStravaTokenManager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JamesRandall%2FStravaTokenManager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JamesRandall","download_url":"https://codeload.github.com/JamesRandall/StravaTokenManager/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225976803,"owners_count":17554283,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-22T23:18:42.482Z","updated_at":"2025-10-16T02:42:35.493Z","avatar_url":"https://github.com/JamesRandall.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Strava Token Manager\n\n![Master build status](https://accidentalfish.visualstudio.com/Strava%20Token%20Manager/_apis/build/status/Build%20and%20Test?branchName=master) Master\n\n![Production build status](https://accidentalfish.visualstudio.com/Strava%20Token%20Manager/_apis/build/status/Build%20and%20Test?branchName=production) Production\n\n_Before reading this guide it is highly recommended you read the [Strava authentication documentation](https://developers.strava.com/docs/authentication/)._\n\nThis package can help you manage the server side part of the Strava authentication flow. Its functionality is accessed by the _ITokenManager_ interface made available through depedendency injection.\n\n## Getting Started\n\nFirst install two NuGet packages:\n\n    Install-Package AccidentalFish.Strava.TokenManager\n    Install-Package AccidentalFish.Strava.TokenManager.AzureTableTokenStore\n\nTo register the dependencies use the _UseStravaTokenManager_ extension method on the _IServiceCollection_ interface, for example:\n\n    IServiceCollection collection = ...; // typically provided by a framework startup system e.g. ASP. Net Core\n    collection.UseStravaTokenManager(new AccidentalFish.Strava.TokenManager.Options {\n        StravaClientId = Environment.GetEnvironmentVariable(\"stravaClientId\"),\n        StravaClientSecret = Environment.GetEnvironmentVariable(\"stravaClientSecret\") // or key vault!\n    });\n\n_In a future version the following step will be optional but for the moment the token manager stores a refresh token and will use it to obtain new access tokens upon access token expiry._\n\nYou will also need to register a persistent store for tokens:\n\n    collection.UseAzureTableStorageTokenRepository(\n        new AccidentalFish.Strava.TokenManager.AzureTableStorageTokenStore.Options\n        {\n            StorageAccountConnectionString = Environment.GetEnvironmentVariable(\"your-storage-connection-string\")\n        });\n\n## Token Exchange - Obtaining an access token\n\nAfter a user has completed the Strava authentication process Strava will redirect to your application and give you a code. This code needs to be sent back to Strava with your client ID and secret to obtain an access token that you can then use to call Strava APIs. The _TokenExchange_ method on the _ITokenManager_ interface can handle this process for you, the following simple class shows the _ITokenManager_ being injected and the code being used to obtain an access token:\n\n    class MyTokenService\n    {\n        private readonly ITokenManager _tokenManager;\n\n        public MyTokenService(ITokenManager tokenManager)\n        {\n            _tokenManager = tokenManager;\n        }\n\n        public async Task\u003cstring\u003e GetAccessTokenFromCode(string code)\n        {\n            TokenSet tokenSet = await _tokenManager.TokenExchange(code);\n            return tokenSet.AccessCode;\n        }\n    }\n\nThe TokenSet class will also has properties that contain the expiry date and time of the access token (_ExpiresAtUtc_) and the athletes Strava ID (_AthleteId_).\n\n## Validating an access token\n\nTypically you will want to ensure that an access token is valid (for example during a REST API call from a client) and you can do this by attempting to retrieve the _TokenSet_ for an access token through the _ITokenManager_ interface:\n\n    public Task\u003cbool\u003e VerifyAccessToken(string accessToken)\n    {\n        TokenSet tokenSet = await _tokenManager.GetTokenSetForAccessToken(accessToken, false);\n        Console.Log($\"Token validated for athlete {tokenSet.AthleteId}\");\n        return true;\n    }\n\nIf the token is invalid for some reason then an exception will be thrown by _GetTokenSetForAccessToken_.\n\nThe second parameter of _GetTokenSetForAccessToken_ indicates to the token manager if the refresh token should be used to renew the access token if it is out of date. This will return a new access token in the _TokenSet_ that you will need to use on subsequent calls. If it is false token renewal will not be attempted.\n\nIf you need to obtain a token during a background process then you can do so using the _GetTokenSetForAthleteId_ method - this behaves in exactly the same way as the _GetTokenSetForAccessToken_ method but accepts an athlete ID rather than an access token.\n\nNote that the refresh token is never returned from the token manager - due to its long life and capability to create a new access token this is a potentially sensitive token, it is therefore not returned to mitigate leakage. If you do need access to the refresh token you can obtain it through the _ITokenRepository_ interface (dependency injectable).\n\n## Caching of tokens\n\nIn a REST API implementation the _GetTokenSetForAccessToken_ call will be called on every REST call and so there is significant benefit in making this a cheap operation. The NuGet package _AccidentalFish.Strava.TokenManager.Abstractions_ exposes an _ITokenCache_ interface that you can use to implement a cache (the methods are fairly self explanatory). An already built Redis based cache is supplied in the _AccidentalFish.Strave.TokenManager.RedisCache_ package. To use this first add the package:\n\n    Install-Package AccidentalFish.Strava.TokenManager\n\nAnd then register it with the _IServiceCollection_:\n\n    collection.UseRedisTokenCache(new AccidentalFish.Strava.TokenManager.RedisCache.Options\n    {\n        RedisConnectionString = Environment.GetEnvironmentVariable(\"redis-connection-string\")\n    });\n\n## Implementing your own token storage repository\n\nThe _AccidentalFish.Strava.TokenManager.Abstractions_ NuGet package exposes an _ITokenRepository_ interface that can be implemented to provide a storage mechanism of your choice. The methods on this interface are fairly self explanatory.\n\n## Code Status\n\nThere are a few improvements I'd like to make and will over time but fundamentally the token manager works in simple projects and it has a set of unit tests. If you come across any issues then please reach out to me on [Twitter](https://twitter.com/AzureTrenches) or use the GitHub Issues here.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesrandall%2Fstravatokenmanager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjamesrandall%2Fstravatokenmanager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesrandall%2Fstravatokenmanager/lists"}