Recently, when a colleague calls the Open API with an iOS app, the server responds with a "invalid_grant" error when it refreshes the access token with refresh token after the access token expires, while in Access If token does not expire, you can refresh access token normally.
Take a look at the "refreshing an Expired Access Token" flowchart in the OAuth specification to confirm that there is a problem with the client's operational process.
The problem occurs in the (G) procedure. The IOS app is just the process of doing it--when invoking the open API, if the server responds to access tokens that are not valid, refresh the access token with refresh token and the client's operating procedure is not a problem.
the problem is then locked to the server. dot write log, found refresh token refreshed access token when the server first called Iauthenticationtokenprovider.receiveasync (), The Ioauthauthorizationserverprovider.grantrefreshtoken () method is then called. The implementation that corresponds to us is Cnblogsrefreshtokenprovider.receiveasync () and Cnblogsauthorizationserverprovider.grantrefreshtoken ().
To view the implementation code for the Receiveasync () method:
public override async Task Receiveasync (Authenticationtokenreceivecontext context) { Span style= "color: #0000ff;" >var refreshtoken = await _ Refreshtokenservice.get (context. Token); if (refreshtoken! = null ) { context. Deserializeticket (Refreshtoken.protectedticket); await _ Refreshtokenservice.remove (context. Token); }}
As you can tell from the code above, refreshing the access token with refresh token is actually the protectedticket that is stored in the database as a ticket containing access tokens. The access token is then generated based on the ticket returned to the client. The refreshtoken.protectedticket is generated by the ticket serialization containing access tokens when the refresh token is generated, and refresh token cannot refresh access token. The problem is likely to be on it.
Then look at the Createasync () method that generates the code--cnblogsrefreshtokenprovider (inherited from Authenticationtokenprovider) of the Refresh token section:
var Refreshtoken = new Refreshtoken () {Id = Refreshtokenid, ClientId = new = context. Ticket.Identity.Name ISSUEDUTC = Datetime.utcnow, EXPIRESUTC = DateTime.UtcNow.AddSeconds (convert.todouble (Refreshtokenlifetime)), Protectedticket = context. Serializeticket () };context. TICKET.PROPERTIES.ISSUEDUTC = Refreshtoken.issuedutc;context. TICKET.PROPERTIES.EXPIRESUTC = REFRESHTOKEN.EXPIRESUTC;
At that time a look at the code, immediately dawned. should be set ISSUEDUTC and EXPIRESUTC first, and then Serializeticket (), the actual is written first serializeticket (), after setting ISSUEDUTC and EXPIRESUTC. The result is that the expiration time of the refreshtoken.protectedticket is incorrect so that access token cannot be refreshed.
The workaround is simple, just the context. Serializeticket () Moves after the code that sets ticket ISSUEDUTC and EXPIRESUTC:
var New Refreshtoken () { = Refreshtokenid, new Guid (clientId), = Context. Ticket.Identity.Name = Datetime.utcnow, = DateTime.UtcNow.AddSeconds ( Convert.todouble (Refreshtokenlifetime)), == refreshtoken.expiresutc; = context. Serializeticket ();
asp: Resolves a problem where refresh token cannot refresh access tokens